ILIAS  trunk Revision v12.0_alpha-1329-g1094ddb0c33
class.ilObjForum.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
26class ilObjForum extends ilObject
27{
30 private static array $obj_id_to_forum_id_cache = [];
32 private static array $ref_id_to_forum_id_cache = [];
34 private static array $forum_statistics_cache = [];
36 private static array $forum_last_post_cache = [];
37 private readonly \ILIAS\DI\RBACServices $rbac;
38 private readonly ilLogger $logger;
39 private readonly ilSetting $settings;
40
41 public function __construct(int $a_id = 0, bool $a_call_by_reference = true)
42 {
43 global $DIC;
44
45 $this->type = 'frm';
46 parent::__construct($a_id, $a_call_by_reference);
47
48 $this->rbac = $DIC->rbac();
49 $this->logger = $DIC->logger()->root();
50
51 $this->settings = $DIC->settings();
52 $this->Forum = new ilForum();
53 }
54
55 public function create(): int
56 {
57 $id = parent::create();
58
59 $properties = ilForumProperties::getInstance($this->getId());
60 $properties->setDefaultView(
61 (int) $this->settings->get('forum_default_view', (string) ilForumProperties::VIEW_DATE_ASC)
62 );
63 $properties->setAnonymisation(false);
64 $properties->setStatisticsStatus(false);
65 $properties->setPostActivation(false);
66 $properties->insert();
67
68 $this->createSettings();
69
70 $this->setOfflineStatus(true);
71 $this->update();
72 $this->saveData();
73
74 return $id;
75 }
76
77 public function setPermissions(int $parent_ref_id): void
78 {
79 parent::setPermissions($parent_ref_id);
80
81 $roles = [self::_lookupModeratorRole($this->getRefId())];
82 $this->rbac->admin()->assignUser($roles[0], $this->getOwner());
83 $this->updateModeratorRole($roles[0]);
84 }
85
86 public function updateModeratorRole(int $role_id): void
87 {
88 $this->db->manipulate(
89 'UPDATE frm_data SET top_mods = ' . $this->db->quote(
90 $role_id,
91 'integer'
92 ) . ' WHERE top_frm_fk = ' . $this->db->quote($this->getId(), 'integer')
93 );
94 }
95
96 public static function _lookupThreadSubject(int $a_thread_id): string
97 {
98 global $DIC;
99
100 $ilDB = $DIC->database();
101
102 $res = $ilDB->queryF('SELECT thr_subject FROM frm_threads WHERE thr_pk = %s', ['integer'], [$a_thread_id]);
103 while ($row = $ilDB->fetchObject($res)) {
104 return $row->thr_subject ?? '';
105 }
106
107 return '';
108 }
109
110 public function getCountUnread(int $a_usr_id, int $a_thread_id = 0, bool $ignoreRoot = false): int
111 {
112 $a_frm_id = $this->getId();
113 $topic_id = 0;
114 $num_posts = 0;
115 $count_read = 0;
116
117 if ($a_thread_id === 0) {
118 $res = $this->db->queryF('SELECT top_pk FROM frm_data WHERE top_frm_fk = %s', ['integer'], [$a_frm_id]);
119 while ($row = $this->db->fetchObject($res)) {
120 $topic_id = (int) $row->top_pk;
121 }
122
123 $res = $this->db->queryF(
124 '
125 SELECT COUNT(pos_pk) num_posts
126 FROM frm_posts
127 LEFT JOIN frm_posts_tree ON frm_posts_tree.pos_fk = pos_pk
128 WHERE pos_top_fk = %s' . ($ignoreRoot ? ' AND parent_pos != 0 ' : ''),
129 ['integer'],
130 [$topic_id]
131 );
132
133 while ($row = $this->db->fetchObject($res)) {
134 $num_posts = (int) $row->num_posts;
135 }
136
137 $res = $this->db->queryF(
138 'SELECT COUNT(post_id) count_read FROM frm_user_read WHERE obj_id = %s AND usr_id = %s',
139 ['integer', 'integer'],
140 [$a_frm_id, $a_usr_id]
141 );
142
143 while ($row = $this->db->fetchObject($res)) {
144 $count_read = (int) $row->count_read;
145 }
146 } else {
147 $res = $this->db->queryF(
148 '
149 SELECT COUNT(pos_pk) num_posts FROM frm_posts
150 LEFT JOIN frm_posts_tree ON frm_posts_tree.pos_fk = pos_pk
151 WHERE pos_thr_fk = %s' . ($ignoreRoot ? ' AND parent_pos != 0 ' : ''),
152 ['integer'],
153 [$a_thread_id]
154 );
155
156 $row = $this->db->fetchObject($res);
157 $num_posts = (int) $row->num_posts;
158
159 $res = $this->db->queryF(
160 '
161 SELECT COUNT(post_id) count_read FROM frm_user_read
162 WHERE obj_id = %s
163 AND usr_id = %s
164 AND thread_id = %s',
165 ['integer', 'integer', 'integer'],
166 [$a_frm_id, $a_frm_id, $a_thread_id]
167 );
168
169 $row = $this->db->fetchObject($res);
170 $count_read = (int) $row->count_read;
171 }
172 $unread = $num_posts - $count_read;
173
174 return max($unread, 0);
175 }
176
177 public function markThreadRead(int $a_usr_id, int $a_thread_id): bool
178 {
179 $res = $this->db->queryF('SELECT pos_pk FROM frm_posts WHERE pos_thr_fk = %s', ['integer'], [$a_thread_id]);
180 while ($row = $this->db->fetchObject($res)) {
181 $this->markPostRead($a_usr_id, $a_thread_id, (int) $row->pos_pk);
182 }
183
184 return true;
185 }
186
187 public function markAllThreadsRead(int $a_usr_id): void
188 {
189 $res = $this->db->queryF(
190 'SELECT thr_pk FROM frm_data, frm_threads WHERE top_frm_fk = %s AND top_pk = thr_top_fk',
191 ['integer'],
192 [$this->getId()]
193 );
194
195 while ($row = $this->db->fetchObject($res)) {
196 $this->markThreadRead($a_usr_id, (int) $row->thr_pk);
197 }
198 }
199
200 public function markPostRead(int $a_usr_id, int $a_thread_id, int $a_post_id): void
201 {
202 $res = $this->db->queryF(
203 '
204 SELECT thread_id FROM frm_user_read
205 WHERE usr_id = %s
206 AND obj_id = %s
207 AND thread_id = %s
208 AND post_id = %s',
209 ['integer', 'integer', 'integer', 'integer'],
210 [$a_usr_id, $this->getId(), $a_thread_id, $a_post_id]
211 );
212
213 if ($this->db->numRows($res) === 0) {
214 $this->db->manipulateF(
215 '
216 INSERT INTO frm_user_read
217 ( usr_id,
218 obj_id,
219 thread_id,
220 post_id
221 )
222 VALUES (%s,%s,%s,%s)',
223 ['integer', 'integer', 'integer', 'integer'],
224 [$a_usr_id, $this->getId(), $a_thread_id, $a_post_id]
225 );
226 }
227 }
228
229 public function markPostUnread(int $a_user_id, int $a_post_id): void
230 {
231 $this->db->manipulateF(
232 'DELETE FROM frm_user_read WHERE usr_id = %s AND post_id = %s',
233 ['integer', 'integer'],
234 [$a_user_id, $a_post_id]
235 );
236 }
237
238 public function isRead($a_usr_id, $a_post_id): bool
239 {
240 $res = $this->db->queryF(
241 'SELECT * FROM frm_user_read WHERE usr_id = %s AND post_id = %s',
242 ['integer', 'integer'],
243 [$a_usr_id, $a_post_id]
244 );
245
246 return (bool) $this->db->numRows($res);
247 }
248
249 public static function _deleteUser(int $a_usr_id): void
250 {
251 global $DIC;
252
253 $data = [$a_usr_id];
254
255 $DIC->database()->manipulateF('DELETE FROM frm_user_read WHERE usr_id = %s', ['integer'], $data);
256 $DIC->database()->manipulateF('DELETE FROM frm_notification WHERE user_id = %s', ['integer'], $data);
257 }
258
259 public static function _deleteReadEntries(int $a_post_id): void
260 {
261 global $DIC;
262
263 $DIC->database()->manipulateF('DELETE FROM frm_user_read WHERE post_id = %s', ['integer'], [$a_post_id]);
264 }
265
266 public function updateModificationUserId(int $usr_id): void
267 {
268 $this->db->manipulateF(
269 'UPDATE frm_data SET update_user = %s WHERE top_frm_fk = %s',
270 ['integer', 'integer'],
271 [$usr_id, $this->getId()],
272 );
273 }
274
275 public function update(): bool
276 {
277 if (parent::update()) {
278 $this->db->manipulateF(
279 'UPDATE frm_data SET top_name = %s, top_description = %s, top_update = %s, update_user = %s WHERE top_frm_fk = %s',
280 ['text', 'text', 'timestamp', 'integer', 'integer'],
281 [
282 $this->getTitle(),
283 $this->getDescription(),
284 date("Y-m-d H:i:s"),
285 $this->user->getId(),
286 $this->getId()
287 ]
288 );
289
290 return true;
291 }
292
293 return false;
294 }
295
296 public function cloneObject(int $target_id, int $copy_id = 0, bool $omit_tree = false): ?ilObject
297 {
299 $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
300 $this->cloneAutoGeneratedRoles($new_obj);
301
302 ilForumProperties::getInstance($this->getId())->copy($new_obj->getId());
303 $this->Forum->setMDB2WhereCondition('top_frm_fk = %s ', ['integer'], [$this->getId()]);
304 $topData = $this->Forum->getOneTopic();
305
306 $this->db->update('frm_data', [
307 'top_name' => ['text', $topData->getTopName()],
308 'top_description' => ['text', $topData->getTopDescription()],
309 'top_num_posts' => ['integer', $topData->getTopNumPosts()],
310 'top_num_threads' => ['integer', $topData->getTopNumThreads()],
311 'top_last_post' => ['text', $topData->getTopLastPost()],
312 'top_date' => ['timestamp', $topData->getTopDate()],
313 'visits' => ['integer', $topData->getVisits()],
314 'top_update' => ['timestamp', $topData->getTopUpdate()],
315 'update_user' => ['integer', $topData->getUpdateUser()],
316 'top_usr_id' => ['integer', $topData->getTopUsrId()]
317 ], [
318 'top_frm_fk' => ['integer', $new_obj->getId()]
319 ]);
320
321 $cwo = ilCopyWizardOptions::_getInstance($copy_id);
322 $options = $cwo->getOptions($this->getRefId());
323
324 $options['threads'] = $this->Forum::getSortedThreadSubjects($this->getId());
325
326 $new_frm = $new_obj->Forum;
327 $new_frm->setMDB2WhereCondition('top_frm_fk = %s ', ['integer'], [$new_obj->getId()]);
328
329 $new_frm->setForumId($new_obj->getId());
330 $new_frm->setForumRefId($new_obj->getRefId());
331
332 $new_topic = $new_frm->getOneTopic();
333 foreach (array_keys($options['threads']) as $thread_id) {
334 $this->Forum->setMDB2WhereCondition('thr_pk = %s ', ['integer'], [$thread_id]);
335
336 $old_thread = $this->Forum->getOneThread();
337
338 $old_post_id = $this->Forum->getRootPostIdByThread($old_thread->getId());
339
340 $newThread = new ilForumTopic(0, true, true);
341 $newThread->setSticky($old_thread->isSticky());
342 $newThread->setForumId($new_topic->getTopPk());
343 $newThread->setThrAuthorId($old_thread->getThrAuthorId());
344 $newThread->setDisplayUserId($old_thread->getDisplayUserId());
345 $newThread->setSubject($old_thread->getSubject());
346 $newThread->setUserAlias($old_thread->getUserAlias());
347 $newThread->setCreateDate($old_thread->getCreateDate());
348
349 try {
350 $top_pos = $old_thread->getFirstVisiblePostNode();
351 } catch (OutOfBoundsException) {
352 $top_pos = new ilForumPost($old_post_id);
353 }
354
355 $newPostId = $new_frm->generateThread(
356 $newThread,
357 $top_pos->getMessage(),
358 $top_pos->isNotificationEnabled(),
359 false,
360 true,
361 (bool) ($old_thread->getNumPosts() - 1)
362 );
363
364 $old_forum_files = new ilFileDataForum($this->getId(), $top_pos->getId());
365 $old_forum_files->ilClone($new_obj->getId(), $newPostId);
366 }
367
368 $source_ref_id = $this->getRefId();
369 $target_ref_id = $new_obj->getRefId();
370 $target_notifications = new ilForumNotification($target_ref_id);
371
372 if ($source_ref_id > 0 && $target_ref_id > 0 && $new_obj->isParentMembershipEnabledContainer()) {
373 if ($this->tree->getParentId($source_ref_id) === $this->tree->getParentId($target_ref_id)) {
374 $target_notifications->cloneFromSource($source_ref_id);
375 } else {
377 $target_notifications->applyTypeConfigurationFor(
378 $new_obj->getAllForumParticipants(),
380 null
381 );
382 }
383 }
384
385 if (ilForumPage::_exists($this->getType(), $this->getId())) {
386 $translations = ilContentPagePage::lookupTranslations($this->getType(), $this->getId());
387 foreach ($translations as $language) {
388 $originalPageObject = new ilForumPage($this->getId(), 0, $language);
389 $copiedXML = $originalPageObject->copyXmlContent();
390
391 $duplicatePageObject = new ilForumPage();
392 $duplicatePageObject->setId($new_obj->getId());
393 $duplicatePageObject->setParentId($new_obj->getId());
394 $duplicatePageObject->setLanguage($language);
395 $duplicatePageObject->setXMLContent($copiedXML);
396 $duplicatePageObject->createFromXML();
397 }
398 }
399
400 $cwo = ilCopyWizardOptions::_getInstance($copy_id);
401 //copy online status if object is not the root copy object
402 if (!$cwo->isRootNode($this->getRefId())) {
403 $new_obj->setOfflineStatus($this->getOfflineStatus());
404 } else {
405 $new_obj->setOfflineStatus(true);
406 }
407 $new_obj->update();
408
409 return $new_obj;
410 }
411
413 {
414 $maybe_grp_ref_id = $this->tree->checkForParentType($this->getRefId(), 'grp');
415 if ($maybe_grp_ref_id > 0) {
416 return true;
417 }
418
419 return $this->tree->checkForParentType($this->getRefId(), 'crs') > 0;
420 }
421
425 public function getAllForumParticipants(): array
426 {
427 $participant_usr_ids = ilForum::_getModerators($this->getRefId());
428
429 try {
430 $participants = $this->parentParticipants();
431 $participant_usr_ids = array_merge(
432 $participant_usr_ids,
433 $participants->getAdmins(),
434 $participants->getMembers(),
435 $participants->getTutors()
436 );
437 } catch (DomainException) {
438 }
439
440 return array_unique($participant_usr_ids);
441 }
442
447 {
449 throw new DomainException('Parent is not a membership enabled container.');
450 }
451
452 $maybe_grp_ref_id = $this->tree->checkForParentType($this->getRefId(), 'grp');
453 if ($maybe_grp_ref_id > 0) {
454 $parent_obj = ilObjectFactory::getInstanceByRefId($maybe_grp_ref_id);
455
456 return ilGroupParticipants::_getInstanceByObjId($parent_obj->getId());
457 }
458
459 $crs_ref_id = $this->tree->checkForParentType($this->getRefId(), 'crs');
460 $parent_obj = ilObjectFactory::getInstanceByRefId($crs_ref_id);
461
462 return ilCourseParticipants::_getInstanceByObjId($parent_obj->getId());
463 }
464
465 public function cloneAutoGeneratedRoles(self $new_obj): void
466 {
467 $src_moderator_role_id = self::_lookupModeratorRole($this->getRefId());
468 $new_moderator_role_id = self::_lookupModeratorRole($new_obj->getRefId());
469
470 if (
471 0 === $src_moderator_role_id ||
472 0 === $new_moderator_role_id ||
473 0 === $this->getRefId() ||
474 0 === $new_obj->getRefId()
475 ) {
476 $this->logger->write(__METHOD__ . ' : Error cloning auto generated role: il_frm_moderator');
477 }
478
479 $this->rbac->admin()->copyRolePermissions(
480 $src_moderator_role_id,
481 $this->getRefId(),
482 $new_obj->getRefId(),
483 $new_moderator_role_id,
484 true
485 );
486
487 $this->logger->write(__METHOD__ . ' : Finished copying of role il_frm_moderator.');
488
489 $moderators = new ilForumModerators($this->getRefId());
490 $src_moderator_usr_ids = $moderators->getCurrentModerators();
491 foreach ($src_moderator_usr_ids as $usr_id) {
492 // The object owner is already member of the moderator role when this method is called
493 // Since the new static caches are introduced with ILIAS 5.0, a database error occurs if we try to assign the user here.
494 if ($this->getOwner() !== $usr_id) {
495 $this->rbac->admin()->assignUser($new_moderator_role_id, $usr_id);
496 }
497 }
498 }
499
500 public function delete(): bool
501 {
502 $this->Forum->setForumId($this->getId());
503
504 if (!parent::delete()) {
505 return false;
506 }
507
508 if (ilForumPage::_exists($this->getType(), $this->getId())) {
509 $originalPageObject = new ilForumPage($this->getId());
510 $originalPageObject->delete();
511 }
512
513 $this->Forum->setMDB2WhereCondition('top_frm_fk = %s ', [ilDBConstants::T_INTEGER], [$this->getId()]);
514
515 $topData = $this->Forum->getOneTopic();
516
517 $threads = $this->Forum->getAllThreads($topData->getTopPk(), [
518 'is_moderator' => true,
519 ]);
520 $thread_ids_to_delete = [];
521 foreach ($threads['items'] as $thread) {
522 $thread_ids_to_delete[$thread->getId()] = $thread->getId();
523 }
524
525 // Get All posting IDs
526 $posting_ids = [];
527 $res = $this->db->query(
528 'SELECT pos_pk FROM frm_posts WHERE '
529 . $this->db->in('pos_thr_fk', $thread_ids_to_delete, false, ilDBConstants::T_INTEGER)
530 );
531
532 while ($row = $res->fetchObject()) {
533 $posting_ids[] = (int) $row->pos_pk;
534 }
535
536 $tmp_file_obj = new ilFileDataForum($this->getId());
537 $tmp_file_obj->delete($posting_ids);
538
539 // Get All draft IDs
540 $draft_ids = [];
541 $res = $this->db->query(
542 'SELECT draft_id FROM frm_posts_drafts WHERE '
543 . $this->db->in('thread_id', $thread_ids_to_delete, false, ilDBConstants::T_INTEGER)
544 );
545
546 while ($row = $res->fetchObject()) {
547 $draft_ids[] = (int) $row->draft_id;
548 }
549
550 $tmp_file_obj = new ilFileDataForumDrafts($this->getId());
551 $tmp_file_obj->delete($draft_ids);
552
553 $this->db->manipulate(
554 'DELETE FROM frm_posts_tree WHERE ' . $this->db->in(
555 'thr_fk',
556 $thread_ids_to_delete,
557 false,
559 )
560 );
561 $this->db->manipulate(
562 'DELETE FROM frm_posts WHERE ' . $this->db->in(
563 'pos_thr_fk',
564 $thread_ids_to_delete,
565 false,
567 )
568 );
569 $this->db->manipulate(
570 'DELETE FROM frm_threads WHERE ' . $this->db->in(
571 'thr_pk',
572 $thread_ids_to_delete,
573 false,
575 )
576 );
577
578 $obj_id = [$this->getId()];
579
580 $this->db->manipulateF('DELETE FROM frm_data WHERE top_frm_fk = %s', [ilDBConstants::T_INTEGER], $obj_id);
581 $this->db->manipulateF('DELETE FROM frm_settings WHERE obj_id = %s', [ilDBConstants::T_INTEGER], $obj_id);
582 $this->db->manipulateF('DELETE FROM frm_user_read WHERE obj_id = %s', [ilDBConstants::T_INTEGER], $obj_id);
583 $this->db->manipulate(
584 'DELETE FROM frm_notification WHERE ' . $this->db->in(
585 'thread_id',
586 $thread_ids_to_delete,
587 false,
588 'integer'
589 )
590 );
591 $this->db->manipulateF('DELETE FROM frm_notification WHERE frm_id = %s', [ilDBConstants::T_INTEGER], $obj_id);
592 $this->db->manipulateF('DELETE FROM frm_posts_deleted WHERE obj_id = %s', [ilDBConstants::T_INTEGER], $obj_id);
593 $this->deleteDraftsByForumId($topData->getTopPk());
594
595 return true;
596 }
597
598 private function deleteDraftsByForumId(int $forum_id): void
599 {
600 $res = $this->db->queryF(
601 'SELECT draft_id FROM frm_posts_drafts WHERE forum_id = %s',
602 ['integer'],
603 [$forum_id]
604 );
605
606 $draft_ids = [];
607 while ($row = $this->db->fetchAssoc($res)) {
608 $draft_ids[] = (int) $row['draft_id'];
609 }
610
611 if ($draft_ids !== []) {
612 $historyObj = new ilForumDraftsHistory();
613 $historyObj->deleteHistoryByDraftIds($draft_ids);
614
615 $draftObj = new ilForumPostDraft();
616 $draftObj->deleteDraftsByDraftIds($draft_ids);
617 }
618 }
619
620 public function initDefaultRoles(): void
621 {
623 'il_frm_moderator_' . $this->getRefId(),
624 "Moderator of forum obj_no." . $this->getId(),
625 'il_frm_moderator',
626 $this->getRefId()
627 );
628 }
629
630 public static function _lookupModeratorRole(int $a_ref_id): int
631 {
632 global $DIC;
633
634 $ilDB = $DIC->database();
635
636 $mod_title = 'il_frm_moderator_' . $a_ref_id;
637
638 $res = $ilDB->queryF('SELECT obj_id FROM object_data WHERE title = %s', ['text'], [$mod_title]);
639 while ($row = $ilDB->fetchObject($res)) {
640 return (int) $row->obj_id;
641 }
642
643 return 0;
644 }
645
646 public function createSettings(): void
647 {
648 global $DIC;
649
650 $ref_id = 0;
651 if ($DIC->http()->wrapper()->query()->has('ref_id')) {
652 $ref_id = $DIC->http()->wrapper()->query()->retrieve(
653 'ref_id',
654 $DIC->refinery()->kindlyTo()->int()
655 );
656 }
657
658 // news settings (public notifications yes/no)
660 if ($default_visibility === 'public') {
661 ilBlockSetting::_write('news', 'public_notifications', '1', 0, $this->getId());
662 }
663 }
664
665 public function saveData(): void
666 {
667 $nextId = $this->db->nextId('frm_data');
668
669 $top_data = [
670 'top_frm_fk' => $this->getId(),
671 'top_name' => $this->getTitle(),
672 'top_description' => $this->getDescription(),
673 'top_num_posts' => 0,
674 'top_num_threads' => 0,
675 'top_last_post' => null,
676 'top_mods' => 0,
677 'top_usr_id' => $this->user->getId(),
678 'top_date' => ilUtil::now()
679 ];
680
681 $this->db->manipulateF(
682 '
683 INSERT INTO frm_data
684 (
685 top_pk,
686 top_frm_fk,
687 top_name,
688 top_description,
689 top_num_posts,
690 top_num_threads,
691 top_last_post,
692 top_mods,
693 top_date,
694 top_usr_id
695 )
696 VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)',
697 [
698 'integer',
699 'integer',
700 'text',
701 'text',
702 'integer',
703 'integer',
704 'text',
705 'integer',
706 'timestamp',
707 'integer'
708 ],
709 [
710 $nextId,
711 $top_data['top_frm_fk'],
712 $top_data['top_name'],
713 $top_data['top_description'],
714 $top_data['top_num_posts'],
715 $top_data['top_num_threads'],
716 $top_data['top_last_post'],
717 $top_data['top_mods'],
718 $top_data['top_date'],
719 $top_data['top_usr_id']
720 ]
721 );
722 }
723
724 public static function lookupForumIdByObjId(int $obj_id): int
725 {
726 if (array_key_exists($obj_id, self::$obj_id_to_forum_id_cache)) {
727 return self::$obj_id_to_forum_id_cache[$obj_id];
728 }
729
731
732 return self::$obj_id_to_forum_id_cache[$obj_id];
733 }
734
735 public static function lookupForumIdByRefId(int $ref_id): int
736 {
737 if (array_key_exists($ref_id, self::$ref_id_to_forum_id_cache)) {
738 return self::$ref_id_to_forum_id_cache[$ref_id];
739 }
740
742
743 return self::$ref_id_to_forum_id_cache[$ref_id];
744 }
745
749 public static function preloadForumIdsByObjIds(array $obj_ids): void
750 {
751 global $DIC;
752
753 $ilDB = $DIC->database();
754
755 if (count($obj_ids) === 1) {
756 $in = ' objr.obj_id = ' . $ilDB->quote(current($obj_ids), 'integer') . ' ';
757 } else {
758 $in = $ilDB->in('objr.obj_id', $obj_ids, false, 'integer');
759 }
760 $query = "
761 SELECT frmd.top_pk, objr.ref_id, objr.obj_id
762 FROM object_reference objr
763 INNER JOIN frm_data frmd ON frmd.top_frm_fk = objr.obj_id
764 WHERE $in
765 ";
766 $res = $ilDB->query($query);
767
768 // Prepare cache array
769 foreach ($obj_ids as $obj_id) {
770 self::$obj_id_to_forum_id_cache[$obj_id] = 0;
771 }
772
773 while ($row = $ilDB->fetchAssoc($res)) {
774 self::$obj_id_to_forum_id_cache[(int) $row['obj_id']] = (int) $row['top_pk'];
775 self::$ref_id_to_forum_id_cache[(int) $row['ref_id']] = (int) $row['top_pk'];
776 }
777 }
778
782 public static function preloadForumIdsByRefIds(array $ref_ids): void
783 {
784 global $DIC;
785
786 $ilDB = $DIC->database();
787
788 if (count($ref_ids) === 1) {
789 $in = " objr.ref_id = " . $ilDB->quote(current($ref_ids), 'integer') . " ";
790 } else {
791 $in = $ilDB->in('objr.ref_id', $ref_ids, false, 'integer');
792 }
793 $query = "
794 SELECT frmd.top_pk, objr.ref_id, objr.obj_id
795 FROM object_reference objr
796 INNER JOIN frm_data frmd ON frmd.top_frm_fk = objr.obj_id
797 WHERE $in
798 ";
799 $res = $ilDB->query($query);
800
801 // Prepare cache array
802 foreach ($ref_ids as $ref_id) {
803 if (!array_key_exists($ref_id, self::$ref_id_to_forum_id_cache)) {
804 self::$ref_id_to_forum_id_cache[$ref_id] = 0;
805 }
806 }
807
808 while ($row = $ilDB->fetchAssoc($res)) {
809 self::$obj_id_to_forum_id_cache[(int) $row['obj_id']] = (int) $row['top_pk'];
810 self::$ref_id_to_forum_id_cache[(int) $row['ref_id']] = (int) $row['top_pk'];
811 }
812 }
813
817 public static function lookupStatisticsByRefId(int $ref_id): array
818 {
819 global $DIC;
820
821 $ilAccess = $DIC->access();
822 $ilUser = $DIC->user();
823 $ilDB = $DIC->database();
824 $ilSetting = $DIC->settings();
825
826 if (isset(self::$forum_statistics_cache[$ref_id])) {
827 return self::$forum_statistics_cache[$ref_id];
828 }
829
830 $statistics = [
831 'num_posts' => 0,
832 'num_unread_posts' => 0,
833 ];
834
836 if ($forumId === 0) {
837 self::$forum_statistics_cache[$ref_id] = $statistics;
838 return self::$forum_statistics_cache[$ref_id];
839 }
840
842 $is_post_activation_enabled = $objProperties->isPostActivationEnabled();
843
844 $act_clause = '';
845
846 if ($is_post_activation_enabled && !$ilAccess->checkAccess('moderate_frm', '', $ref_id)) {
847 $act_clause .= ' AND (frm_posts.pos_status = ' . $ilDB->quote(
848 1,
849 'integer'
850 ) . ' OR frm_posts.pos_author_id = ' . $ilDB->quote($ilUser->getId(), 'integer') . ') ';
851 }
852
853 if (!$ilUser->isAnonymous()) {
854 $query = "
855 (SELECT COUNT(frm_posts.pos_pk) cnt
856 FROM frm_posts
857 INNER JOIN frm_posts_tree tree1
858 ON tree1.pos_fk = frm_posts.pos_pk
859 AND tree1.parent_pos != 0
860 INNER JOIN frm_threads ON frm_posts.pos_thr_fk = frm_threads.thr_pk
861 WHERE frm_threads.thr_top_fk = %s $act_clause)
862
863 UNION ALL
864
865 (SELECT COUNT(DISTINCT(frm_user_read.post_id)) cnt
866 FROM frm_user_read
867 INNER JOIN frm_posts ON frm_user_read.post_id = frm_posts.pos_pk
868 INNER JOIN frm_posts_tree tree1
869 ON tree1.pos_fk = frm_posts.pos_pk
870 AND tree1.parent_pos != 0
871 INNER JOIN frm_threads ON frm_threads.thr_pk = frm_posts.pos_thr_fk
872 WHERE frm_user_read.usr_id = %s AND frm_posts.pos_top_fk = %s $act_clause)
873 ";
874
875 $types = ['integer', 'integer', 'integer'];
876 $values = [$forumId, $ilUser->getId(), $forumId];
877
878 $mapping = array_keys($statistics);
879 $res = $ilDB->queryF(
880 $query,
881 $types,
882 $values
883 );
884 for ($i = 0; $i < 2; $i++) {
885 $row = $ilDB->fetchAssoc($res);
886
887 $statistics[$mapping[$i]] = (int) ((is_array($row) ? $row['cnt'] : 0));
888
889 if ($i === 1) {
890 // unread = all - read
891 $statistics[$mapping[$i]] = $statistics[$mapping[$i - 1]] - $statistics[$mapping[$i]];
892 }
893 }
894 } else {
895 $query = "
896 SELECT COUNT(frm_posts.pos_pk) cnt
897 FROM frm_posts
898 INNER JOIN frm_posts_tree tree1
899 ON tree1.pos_fk = frm_posts.pos_pk
900 AND tree1.parent_pos != 0
901 INNER JOIN frm_threads ON frm_posts.pos_thr_fk = frm_threads.thr_pk
902 WHERE frm_threads.thr_top_fk = %s $act_clause
903 ";
904 $types = ['integer'];
905 $values = [$forumId];
906 $res = $ilDB->queryF(
907 $query,
908 $types,
909 $values
910 );
911 $row = $ilDB->fetchAssoc($res);
912
913 $statistics = [
914 'num_posts' => (int) $row['cnt'],
915 'num_unread_posts' => (int) $row['cnt'],
916 ];
917 }
918
919 self::$forum_statistics_cache[$ref_id] = $statistics;
920
921 return self::$forum_statistics_cache[$ref_id];
922 }
923
924 public static function lookupLastPostByRefId(int $ref_id): ?array
925 {
926 global $DIC;
927
928 $ilAccess = $DIC->access();
929 $ilUser = $DIC->user();
930 $ilDB = $DIC->database();
931
932 if (array_key_exists($ref_id, self::$forum_last_post_cache)) {
933 return self::$forum_last_post_cache[$ref_id];
934 }
935
937 if ($forumId === 0) {
938 self::$forum_last_post_cache[$ref_id] = null;
939 return self::$forum_last_post_cache[$ref_id];
940 }
941
942 $act_clause = '';
943 if (!$ilAccess->checkAccess('moderate_frm', '', $ref_id)) {
944 $act_clause .= ' AND (frm_posts.pos_status = ' . $ilDB->quote(
945 1,
946 'integer'
947 ) . ' OR frm_posts.pos_author_id = ' . $ilDB->quote($ilUser->getId(), 'integer') . ') ';
948 }
949
950 $ilDB->setLimit(1, 0);
951 $query = "
952 SELECT *
953 FROM frm_posts
954 INNER JOIN frm_posts_tree tree1
955 ON tree1.pos_fk = frm_posts.pos_pk
956 AND tree1.parent_pos != 0
957 WHERE pos_top_fk = %s $act_clause
958 ORDER BY pos_date DESC
959 ";
960 $res = $ilDB->queryF(
961 $query,
962 ['integer'],
963 [$forumId]
964 );
965
966 $data = $ilDB->fetchAssoc($res);
967 if (!is_array($data) || empty($data)) {
968 self::$forum_last_post_cache[$ref_id] = null;
969 return self::$forum_last_post_cache[$ref_id];
970 }
971
972 $casted_data = [];
973 $casted_data['pos_pk'] = (int) $data['pos_pk'];
974 $casted_data['pos_top_fk'] = (int) $data['pos_top_fk'];
975 $casted_data['pos_thr_fk'] = (int) $data['pos_thr_fk'];
976 $casted_data['pos_usr_alias'] = (string) $data['pos_usr_alias'];
977 $casted_data['pos_subject'] = (string) $data['pos_subject'];
978 $casted_data['pos_date'] = (string) $data['pos_date'];
979 $casted_data['pos_update'] = (string) $data['pos_update'];
980 $casted_data['update_user'] = (int) $data['update_user'];
981 $casted_data['pos_cens'] = (int) $data['pos_cens'];
982 $casted_data['pos_cens_com'] = (string) $data['pos_cens_com'];
983 $casted_data['notify'] = (int) $data['notify'];
984 $casted_data['import_name'] = (string) $data['import_name'];
985 $casted_data['pos_status'] = (int) $data['pos_status'];
986 $casted_data['pos_message'] = (string) $data['pos_message'];
987 $casted_data['pos_author_id'] = (int) $data['pos_author_id'];
988 $casted_data['pos_display_user_id'] = (int) $data['pos_display_user_id'];
989 $casted_data['is_author_moderator'] = (int) $data['is_author_moderator'];
990 $casted_data['pos_cens_date'] = (string) $data['pos_cens_date'];
991 $casted_data['pos_activation_date'] = (string) $data['pos_activation_date'];
992
993 self::$forum_last_post_cache[$ref_id] = $casted_data;
994
995 return self::$forum_last_post_cache[$ref_id];
996 }
997
1002 public static function getUserIdsOfLastPostsByRefIdAndThreadIds(int $ref_id, array $thread_ids): array
1003 {
1004 global $DIC;
1005
1006 $ilAccess = $DIC->access();
1007 $ilUser = $DIC->user();
1008 $ilDB = $DIC->database();
1009
1010 $act_clause = '';
1011 $act_inner_clause = '';
1012 if (!$ilAccess->checkAccess('moderate_frm', '', $ref_id)) {
1013 $act_clause .= " AND (t1.pos_status = " . $ilDB->quote(
1014 1,
1015 "integer"
1016 ) . " OR t1.pos_author_id = " . $ilDB->quote($ilUser->getId(), "integer") . ") ";
1017 $act_inner_clause .= " AND (t3.pos_status = " . $ilDB->quote(
1018 1,
1019 "integer"
1020 ) . " OR t3.pos_author_id = " . $ilDB->quote($ilUser->getId(), "integer") . ") ";
1021 }
1022
1023 $in = $ilDB->in("t1.pos_thr_fk", $thread_ids, false, 'integer');
1024 $inner_in = $ilDB->in("t3.pos_thr_fk", $thread_ids, false, 'integer');
1025
1026 $query = "
1027 SELECT t1.pos_display_user_id, t1.update_user
1028 FROM frm_posts t1
1029 INNER JOIN frm_posts_tree tree1 ON tree1.pos_fk = t1.pos_pk AND tree1.parent_pos != 0
1030 INNER JOIN (
1031 SELECT t3.pos_thr_fk, MAX(t3.pos_date) pos_date
1032 FROM frm_posts t3
1033 INNER JOIN frm_posts_tree tree2 ON tree2.pos_fk = t3.pos_pk AND tree2.parent_pos != 0
1034 WHERE $inner_in $act_inner_clause
1035 GROUP BY t3.pos_thr_fk
1036 ) t2 ON t2.pos_thr_fk = t1.pos_thr_fk AND t2.pos_date = t1.pos_date
1037 WHERE $in $act_clause
1038 GROUP BY t1.pos_thr_fk, t1.pos_display_user_id, t1.update_user
1039 ";
1040
1041 $usr_ids = [];
1042
1043 $res = $ilDB->query($query);
1044 while ($row = $ilDB->fetchAssoc($res)) {
1045 if ((int) $row['pos_display_user_id'] !== 0) {
1046 $usr_ids[] = (int) $row['pos_display_user_id'];
1047 }
1048 if ((int) $row['update_user'] !== 0) {
1049 $usr_ids[] = (int) $row['update_user'];
1050 }
1051 }
1052
1053 return array_unique($usr_ids);
1054 }
1055
1056 public static function mergeForumUserRead(int $merge_source_thread_id, int $merge_target_thread_id): void
1057 {
1058 global $DIC;
1059
1060 $DIC->database()->update(
1061 'frm_user_read',
1062 ['thread_id' => ['integer', $merge_target_thread_id]],
1063 ['thread_id' => ['integer', $merge_source_thread_id]]
1064 );
1065 }
1066
1067 public function getNumStickyThreads(): int
1068 {
1069 $res = $this->db->query(
1070 'SELECT COUNT(is_sticky) num_sticky FROM frm_threads
1071 INNER JOIN frm_data ON top_pk = thr_top_fk
1072 WHERE frm_data.top_frm_fk = ' . $this->db->quote($this->getId(), 'integer') . '
1073 AND is_sticky = ' . $this->db->quote(1, 'integer')
1074 );
1075 if ($row = $this->db->fetchAssoc($res)) {
1076 return (int) $row['num_sticky'];
1077 }
1078
1079 return 0;
1080 }
1081
1085 public function getPageObjIds(): array
1086 {
1087 $pageObjIds = [];
1088
1089 $sql = 'SELECT DISTINCT page_id FROM page_object WHERE parent_id = %s AND parent_type = %s';
1090 $res = $this->db->queryF(
1091 $sql,
1092 ['integer', 'text'],
1093 [$this->getId(), $this->getType()]
1094 );
1095
1096 while ($row = $this->db->fetchAssoc($res)) {
1097 $pageObjIds[] = (int) $row['page_id'];
1098 }
1099
1100 return $pageObjIds;
1101 }
1102}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
static _write(string $a_type, string $a_setting, string $a_value, int $a_user=0, int $a_block_id=0)
Write setting to database.
static _getInstance(int $a_copy_id)
static _getInstanceByObjId(int $a_obj_id)
Class ilForumDraftHistory.
Class ilForumModerators.
Class ilForumNotification.
Class ilForumPostDraft.
static getInstance(int $a_obj_id=0)
Class Forum core functions for forum.
static _getModerators(int $a_ref_id)
static _getInstanceByObjId(int $a_obj_id)
Get singleton instance.
Component logger with individual log levels by component id.
static _getDefaultVisibilityForRefId(int $a_ref_id)
Get default visibility for reference id.
Class ilObjForum.
static _deleteReadEntries(int $a_post_id)
__construct(int $a_id=0, bool $a_call_by_reference=true)
static lookupForumIdByRefId(int $ref_id)
static lookupForumIdByObjId(int $obj_id)
cloneAutoGeneratedRoles(self $new_obj)
static array $ref_id_to_forum_id_cache
markAllThreadsRead(int $a_usr_id)
initDefaultRoles()
init default roles settings Purpose of this function is to create a local role folder and local roles...
readonly ILIAS DI RBACServices $rbac
markThreadRead(int $a_usr_id, int $a_thread_id)
static _lookupModeratorRole(int $a_ref_id)
readonly ilLogger $logger
static lookupStatisticsByRefId(int $ref_id)
static preloadForumIdsByRefIds(array $ref_ids)
static getUserIdsOfLastPostsByRefIdAndThreadIds(int $ref_id, array $thread_ids)
static array $forum_statistics_cache
updateModeratorRole(int $role_id)
deleteDraftsByForumId(int $forum_id)
setPermissions(int $parent_ref_id)
isRead($a_usr_id, $a_post_id)
readonly ilSetting $settings
isParentMembershipEnabledContainer()
static lookupLastPostByRefId(int $ref_id)
getCountUnread(int $a_usr_id, int $a_thread_id=0, bool $ignoreRoot=false)
static array $obj_id_to_forum_id_cache
static _lookupThreadSubject(int $a_thread_id)
static mergeForumUserRead(int $merge_source_thread_id, int $merge_target_thread_id)
static preloadForumIdsByObjIds(array $obj_ids)
updateModificationUserId(int $usr_id)
markPostRead(int $a_usr_id, int $a_thread_id, int $a_post_id)
static _deleteUser(int $a_usr_id)
static array $forum_last_post_cache
create()
note: title, description and type should be set when this function is called
markPostUnread(int $a_user_id, int $a_post_id)
static createDefaultRole(string $a_title, string $a_description, string $a_tpl_name, int $a_ref_id)
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
Class ilObject Basic functions for all objects.
static _lookupObjectId(int $ref_id)
Properties $object_properties
setOfflineStatus(bool $status)
static _exists(string $a_parent_type, int $a_id, string $a_lang="", bool $a_no_cache=false)
Checks whether page exists.
static lookupTranslations(string $a_parent_type, int $a_id)
Lookup translations.
Base class for course and group participants.
ILIAS Setting Class.
static now()
Return current timestamp in Y-m-d H:i:s format.
$res
Definition: ltiservices.php:69
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $ilSetting
Definition: privfeed.php:26
global $DIC
Definition: shib_login.php:26