ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilForumTopic.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
26{
27 private static array $possibleOrderDirections = ['ASC', 'DESC'];
28
29 private int $forum_id = 0;
30 private int $frm_obj_id = 0;
31 private int $display_user_id = 0;
32 private ?string $user_alias = null;
33 private string $subject = '';
34 private ?string $createdate = null;
35 private ?string $changedate = null;
36 private int $num_posts = 0;
37 private ?string $last_post_string = null;
38 private int $visits = 0;
39 private ?string $import_name = null;
40 private bool $is_sticky = false;
41 private bool $is_closed = false;
42 private string $orderField = '';
43 private ?ilForumPost $last_post = null;
44 private readonly ilDBInterface $db;
45 private int $thr_author_id = 0;
46 private float $average_rating = 0.0;
47 private string $orderDirection = 'DESC';
48 private readonly ilObjUser $user;
49 private int $num_unread_posts = 0;
50 private bool $user_notification_enabled = false;
51
59 public function __construct(
60 private int $id = 0,
61 private readonly bool $is_moderator = false,
62 bool $preventImplicitRead = false
63 ) {
64 global $DIC;
65 $this->db = $DIC->database();
66 $this->user = $DIC->user();
67
68 if (!$preventImplicitRead) {
69 $this->read();
70 }
71 }
72
73 public function assignData(array $data): void
74 {
75 $this->setId((int) $data['thr_pk']);
76 $this->setForumId((int) $data['thr_top_fk']);
77 $this->setSubject($data['thr_subject']);
78 $this->setDisplayUserId((int) $data['thr_display_user_id']);
79 $this->setUserAlias($data['thr_usr_alias']);
80 $this->setLastPostString($data['thr_last_post']);
81 $this->setCreateDate($data['thr_date']);
82 $this->setChangeDate($data['thr_update']);
83 $this->setVisits((int) $data['visits']);
84 $this->setImportName($data['import_name']);
85 $this->setSticky((bool) $data['is_sticky']);
86 $this->setClosed((bool) $data['is_closed']);
87 $this->setAverageRating(isset($data['avg_rating']) ? (float) $data['avg_rating'] : 0);
88 $this->setThrAuthorId((int) $data['thr_author_id']);
89
90 // Aggregated values
91 if (isset($data['num_posts'])) {
92 $this->setNumPosts((int) $data['num_posts']);
93 }
94 if (isset($data['num_unread_posts'])) {
95 $this->setNumUnreadPosts((int) $data['num_unread_posts']);
96 }
97 if (isset($data['usr_notification_is_enabled'])) {
98 $this->setUserNotificationEnabled((bool) $data['usr_notification_is_enabled']);
99 }
100 }
101
102 public function insert(): bool
103 {
104 if ($this->forum_id !== 0) {
105 $nextId = $this->db->nextId('frm_threads');
106
107 $this->db->insert(
108 'frm_threads',
109 [
110 'thr_pk' => ['integer', $nextId],
111 'thr_top_fk' => ['integer', $this->forum_id],
112 'thr_subject' => ['text', $this->subject],
113 'thr_display_user_id' => ['integer', $this->display_user_id],
114 'thr_usr_alias' => ['text', $this->user_alias],
115 'thr_num_posts' => ['integer', $this->num_posts],
116 'thr_last_post' => ['text', $this->last_post_string],
117 'thr_date' => ['timestamp', $this->createdate],
118 'thr_update' => ['timestamp', null],
119 'import_name' => ['text', $this->import_name],
120 'is_sticky' => ['integer', (int) $this->is_sticky],
121 'is_closed' => ['integer', (int) $this->is_closed],
122 'avg_rating' => ['text', (string) $this->average_rating],
123 'thr_author_id' => ['integer', $this->thr_author_id]
124 ]
125 );
126
127 $this->id = $nextId;
128
129 return true;
130 }
131
132 return false;
133 }
134
135 public function update(): bool
136 {
137 if ($this->id !== 0) {
138 $this->db->manipulateF(
139 '
140 UPDATE frm_threads
141 SET thr_top_fk = %s,
142 thr_subject = %s,
143 thr_update = %s,
144 thr_num_posts = %s,
145 thr_last_post = %s,
146 avg_rating = %s
147 WHERE thr_pk = %s',
148 ['integer', 'text', 'timestamp', 'integer', 'text', 'text', 'integer'],
149 [
150 $this->forum_id,
151 $this->subject,
152 date('Y-m-d H:i:s'),
153 $this->num_posts,
154 $this->last_post_string,
155 (string) $this->average_rating,
156 $this->id
157 ]
158 );
159
160 return true;
161 }
162
163 return false;
164 }
165
166 private function read(): bool
167 {
168 if ($this->id !== 0) {
169 $res = $this->db->queryF(
170 '
171 SELECT frm_threads.*, top_frm_fk frm_obj_id
172 FROM frm_threads
173 INNER JOIN frm_data ON top_pk = thr_top_fk
174 WHERE thr_pk = %s',
175 ['integer'],
176 [$this->id]
177 );
178
179 $row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT);
180
181 if (is_object($row)) {
182 $this->forum_id = (int) $row->thr_top_fk;
183 $this->display_user_id = (int) $row->thr_display_user_id;
184 $this->user_alias = $row->thr_usr_alias;
185 $this->subject = html_entity_decode((string) $row->thr_subject);
186 $this->createdate = $row->thr_date;
187 $this->changedate = $row->thr_update;
188 $this->import_name = $row->import_name;
189 $this->num_posts = (int) $row->thr_num_posts;
190 $this->last_post_string = $row->thr_last_post;
191 $this->visits = (int) $row->visits;
192 $this->is_sticky = (bool) $row->is_sticky;
193 $this->is_closed = (bool) $row->is_closed;
194 $this->frm_obj_id = (int) $row->frm_obj_id;
195 $this->average_rating = (float) $row->avg_rating;
196 $this->thr_author_id = (int) $row->thr_author_id;
197
198 return true;
199 }
200 $this->id = 0;
201 return false;
202 }
203
204 return false;
205 }
206
207 public function reload(): bool
208 {
209 return $this->read();
210 }
211
212 public function getPostRootId(): int
213 {
214 $this->db->setLimit(1);
215 $res = $this->db->queryF(
216 'SELECT pos_fk FROM frm_posts_tree WHERE thr_fk = %s AND parent_pos = %s AND depth = %s ORDER BY rgt DESC',
217 ['integer', 'integer', 'integer'],
218 [$this->id, 0, 1]
219 );
220
221 if (($row = $this->db->fetchObject($res)) !== null) {
222 return (int) $row->pos_fk ?: 0;
223 }
224 return 0;
225 }
226
227 public function getFirstVisiblePostId(): int
228 {
229 $this->db->setLimit(1);
230 $res = $this->db->queryF(
231 'SELECT pos_fk FROM frm_posts_tree WHERE thr_fk = %s AND parent_pos != %s AND depth = %s ORDER BY rgt DESC',
232 ['integer', 'integer', 'integer'],
233 [$this->id, 0, 2]
234 );
235
236 if (($row = $this->db->fetchObject($res)) !== null) {
237 return (int) $row->pos_fk ?: 0;
238 }
239 return 0;
240 }
241
242 public function updateVisits(): void
243 {
244 $checkTime = time() - (60 * 60);
245
246 if (ilSession::get('frm_visit_frm_threads_' . $this->id) < $checkTime) {
247 ilSession::set('frm_visit_frm_threads_' . $this->id, time());
248
249 $this->db->manipulateF(
250 'UPDATE frm_threads SET visits = visits + 1 WHERE thr_pk = %s',
251 ['integer'],
252 [$this->id]
253 );
254 }
255 }
256
257 public function countPosts(bool $ignoreRoot = false): int
258 {
259 $res = $this->db->queryF(
260 '
261 SELECT COUNT(*) cnt
262 FROM frm_posts
263 INNER JOIN frm_posts_tree ON frm_posts_tree.pos_fk = pos_pk
264 WHERE pos_thr_fk = %s' . ($ignoreRoot ? ' AND parent_pos != 0 ' : ''),
265 ['integer'],
266 [$this->id]
267 );
268
269 $row = $this->db->fetchAssoc($res);
270 if (is_array($row)) {
271 return (int) $row['cnt'];
272 }
273
274 return 0;
275 }
276
277 public function countActivePosts(bool $ignoreRoot = false): int
278 {
279 $res = $this->db->queryF(
280 '
281 SELECT COUNT(*) cnt
282 FROM frm_posts
283 INNER JOIN frm_posts_tree ON frm_posts_tree.pos_fk = pos_pk
284 WHERE (pos_status = %s
285 OR (pos_status = %s AND pos_display_user_id = %s))
286 AND pos_thr_fk = %s' . ($ignoreRoot ? ' AND parent_pos != 0 ' : ''),
287 ['integer', 'integer', 'integer', 'integer'],
288 ['1', '0', $this->user->getId(), $this->id]
289 );
290
291 $row = $this->db->fetchAssoc($res);
292 if (is_array($row)) {
293 return (int) $row['cnt'];
294 }
295
296 return 0;
297 }
298
299 public function getPostRootNode(bool $isModerator = false, bool $preventImplicitRead = false): ilForumPost
300 {
301 $this->db->setLimit(1);
302 $res = $this->db->queryF(
303 '
304 SELECT *
305 FROM frm_posts
306 INNER JOIN frm_posts_tree ON pos_fk = pos_pk
307 WHERE parent_pos = %s
308 AND thr_fk = %s
309 ORDER BY rgt DESC',
310 ['integer', 'integer'],
311 [0, $this->id]
312 );
313
314 if ($row = $this->db->fetchAssoc($res)) {
315 $post = new ilForumPost((int) $row['pos_pk'], $isModerator, $preventImplicitRead);
316 $post->assignData($row);
317 return $post;
318 }
319
320 throw new OutOfBoundsException(sprintf('Could not find first posting by id: %s', $this->id));
321 }
322
323 public function getFirstVisiblePostNode(bool $isModerator = false, bool $preventImplicitRead = false): ilForumPost
324 {
325 $this->db->setLimit(1);
326 $res = $this->db->queryF(
327 '
328 SELECT *
329 FROM frm_posts
330 INNER JOIN frm_posts_tree ON pos_fk = pos_pk
331 WHERE parent_pos != %s
332 AND thr_fk = %s
333 AND depth = %s
334 ORDER BY rgt DESC',
335 ['integer', 'integer', 'integer'],
336 [0, $this->id, 2]
337 );
338
339 if ($row = $this->db->fetchAssoc($res)) {
340 $post = new ilForumPost((int) $row['pos_pk'], $isModerator, $preventImplicitRead);
341 $post->assignData($row);
342 return $post;
343 }
344
345 throw new OutOfBoundsException(sprintf('Could not find first posting by id: %s', $this->id));
346 }
347
348 public function getLastPost(): ilForumPost
349 {
350 if ($this->id !== 0) {
351 $this->db->setLimit(1);
352 $res = $this->db->queryF(
353 'SELECT pos_pk FROM frm_posts WHERE pos_thr_fk = %s ORDER BY pos_date DESC',
354 ['integer'],
355 [$this->id]
356 );
357
358 if (($row = $this->db->fetchObject($res)) !== null) {
359 return new ilForumPost((int) $row->pos_pk);
360 }
361 }
362
363 throw new OutOfBoundsException(sprintf('Could not find last posting by id: %s', $this->id));
364 }
365
367 {
368 if ($this->id !== 0) {
369 $this->db->setLimit(1);
370 $res = $this->db->queryF(
371 '
372 SELECT pos_pk
373 FROM frm_posts
374 WHERE pos_thr_fk = %s
375 AND (pos_status = %s OR (pos_status = %s AND pos_display_user_id = %s))
376 ORDER BY pos_date DESC',
377 ['integer', 'integer', 'integer', 'integer'],
378 [$this->id, '1', '0', $this->user->getId()]
379 );
380
381 if (($row = $this->db->fetchObject($res)) !== null) {
382 return new ilForumPost((int) $row->pos_pk);
383 }
384 }
385
386 throw new OutOfBoundsException(sprintf('Could not find last active posting by id: %s', $this->id));
387 }
388
392 public function getAllPostIds(): array
393 {
394 $posts = [];
395
396 if ($this->id !== 0) {
397 $res = $this->db->queryF('SELECT pos_pk FROM frm_posts WHERE pos_thr_fk = %s', ['integer'], [$this->id]);
398
399 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
400 $posts[(int) $row->pos_pk] = (int) $row->pos_pk;
401 }
402 }
403
404 return $posts;
405 }
406
413 public function getPostTree(ilForumPost $a_post_node): array
414 {
415 $posts = [];
416 $data = [];
417 $data_types = [];
418
419 if ($a_post_node->getLft() > 1) {
420 $dummy_root_condition = 'lft >= %s AND lft < %s';
421 } else {
422 $dummy_root_condition = 'lft > %s AND lft < %s';
423 }
424
425 $query = '
426 SELECT is_author_moderator, pos_author_id, pos_pk, fpt_date, rgt, pos_top_fk, pos_thr_fk,
427 pos_display_user_id, pos_usr_alias, pos_subject,
428 pos_status, pos_message, pos_date, pos_update, rcid,
429 update_user, pos_cens, pos_cens_com, notify,
430 import_name, fpt_pk, parent_pos, lft, depth,
431 (CASE
432 WHEN fur.post_id IS NULL ' .
433 ($this->user->getId() === ANONYMOUS_USER_ID ? ' AND 1 = 2 ' : '') . '
434 THEN 0
435 ELSE 1
436 END) post_read,
437 firstname, lastname, title, login
438
439 FROM frm_posts_tree
440
441 INNER JOIN frm_posts
442 ON pos_fk = pos_pk
443
444 LEFT JOIN usr_data
445 ON pos_display_user_id = usr_id
446
447 LEFT JOIN frm_user_read fur
448 ON fur.thread_id = pos_thr_fk
449 AND fur.post_id = pos_pk
450 AND fur.usr_id = %s
451
452 WHERE ' . $dummy_root_condition . '
453 AND thr_fk = %s';
454 $data_types[] = 'integer';
455 $data_types[] = 'integer';
456 $data_types[] = 'integer';
457 $data_types[] = 'integer';
458 $data[] = $this->user->getId();
459 $data[] = $a_post_node->getLft();
460 $data[] = $a_post_node->getRgt();
461 $data[] = $a_post_node->getThreadId();
462
463 if ($this->orderField !== '') {
464 $query .= " ORDER BY " . $this->orderField . " " . $this->getOrderDirection();
465 }
466
467 $res = $this->db->queryF($query, $data_types, $data);
468
469 $usr_ids = [];
470 while ($row = $this->db->fetchAssoc($res)) {
471 $post = new ilForumPost((int) $row['pos_pk'], false, true);
472 $post->assignData($row);
473
474 if (!$this->is_moderator && !$post->isActivated() && $post->getPosAuthorId() !== $this->user->getId()) {
475 continue;
476 }
477
478 if ((int) $row['pos_display_user_id'] !== 0) {
479 $usr_ids[(int) $row['pos_display_user_id']] = (int) $row['pos_display_user_id'];
480 }
481 if ((int) $row['update_user'] !== 0) {
482 $usr_ids[(int) $row['update_user']] = (int) $row['update_user'];
483 }
484
485 $posts[] = $post;
486 }
487
489
490 return $posts;
491 }
492
502 public function movePosts(int $old_obj_id, int $old_pk, int $new_obj_id, int $new_pk): int
503 {
504 if ($this->id === 0) {
505 return 0;
506 }
507
508 $post_ids = $this->getAllPostIds();
509 $postsMoved = [];
510 try {
511 foreach ($post_ids as $post_id) {
512 $file_obj = new ilFileDataForum($old_obj_id, $post_id);
513 $moved = $file_obj->moveFilesOfPost($new_obj_id);
514
515 if ($moved) {
516 $postsMoved[] = [
517 'from' => $old_obj_id,
518 'to' => $new_obj_id,
519 'position_id' => $post_id
520 ];
521 }
522
523 unset($file_obj);
524 }
525 } catch (ilFileUtilsException $exception) {
526 foreach ($postsMoved as $postedInformation) {
527 $file_obj = new ilFileDataForum($postedInformation['to'], $postedInformation['position_id']);
528 $file_obj->moveFilesOfPost($postedInformation['from']);
529 }
530
531 throw $exception;
532 }
533
534 $current_id = $this->id;
535
536 $ilAtomQuery = $this->db->buildAtomQuery();
537 $ilAtomQuery->addTableLock('frm_user_read');
538
539 $ilAtomQuery->addQueryCallable(static function (ilDBInterface $ilDB) use ($new_obj_id, $current_id): void {
540 $ilDB->manipulateF(
541 'DELETE FROM frm_user_read WHERE obj_id = %s AND thread_id =%s',
542 ['integer', 'integer'],
543 [$new_obj_id, $current_id]
544 );
545
546 $ilDB->manipulateF(
547 'UPDATE frm_user_read SET obj_id = %s WHERE thread_id = %s',
548 ['integer', 'integer'],
549 [$new_obj_id, $current_id]
550 );
551 });
552
553 $ilAtomQuery->run();
554
555 $this->db->manipulateF(
556 'UPDATE frm_posts SET pos_top_fk = %s WHERE pos_thr_fk = %s',
557 ['integer', 'integer'],
558 [$new_pk, $this->id]
559 );
560
561 $res = $this->db->queryF(
562 'SELECT * FROM frm_posts WHERE pos_thr_fk = %s',
563 ['integer'],
564 [$this->id]
565 );
566
567 $old_obj_id = ilForum::_lookupObjIdForForumId($old_pk);
568 $new_obj_id = ilForum::_lookupObjIdForForumId($new_pk);
569
570 while ($post = $this->db->fetchAssoc($res)) {
572 $old_obj_id,
573 'frm',
574 (int) $post['pos_pk'],
575 'pos'
576 );
577 $news_item = new ilNewsItem($news_id);
578 $news_item->setContextObjId($new_obj_id);
579 $news_item->update();
580 }
581
582 return count($post_ids);
583 }
584
585 public function getNestedSetPostChildren(?int $pos_id = null, ?int $num_levels = null): array
586 {
587 $data = null;
588 $objProperties = ilForumProperties::getInstance($this->getFrmObjId());
589 $is_post_activation_enabled = $objProperties->isPostActivationEnabled();
590
591 if ($pos_id !== null) {
592 $res = $this->db->queryF(
593 "
594 SELECT lft, rgt, depth
595 FROM frm_posts_tree
596 WHERE pos_fk = %s
597 AND thr_fk = %s",
598 ['integer', 'integer'],
599 [$pos_id, $this->id]
600 );
601
602 $data = $this->db->fetchAssoc($res);
603 }
604
605 $query = '
606 SELECT fpt.depth,
607 fpt.rgt,
608 fpt.parent_pos,
609 fp.pos_pk,
610 fp.pos_subject,
611 fp.pos_usr_alias,
612 fp.pos_date,
613 fp.pos_update,
614 fp.pos_status,
615 fp.pos_display_user_id,
616 fp.pos_usr_alias,
617 fp.import_name,
618 fp.pos_author_id,
619 fp.is_author_moderator,
620 fur.post_id,
621 (CASE
622 WHEN fur.post_id IS NULL ' .
623 ($this->user->getId() === ANONYMOUS_USER_ID ? ' AND 1 = 2 ' : '') . '
624 THEN 0
625 ELSE 1
626 END) post_read,
627 COUNT(fpt2.pos_fk) children
628
629 FROM frm_posts_tree fpt
630
631 INNER JOIN frm_posts fp
632 ON fp.pos_pk = fpt.pos_fk
633
634 LEFT JOIN frm_posts_tree fpt2
635 ON fpt2.lft BETWEEN fpt.lft AND fpt.rgt
636 AND fpt.thr_fk = fpt2.thr_fk
637 AND fpt.pos_fk != fpt2.pos_fk ';
638
639 $query .= '
640 LEFT JOIN frm_user_read fur
641 ON fur.thread_id = fp.pos_thr_fk
642 AND fur.post_id = fp.pos_pk
643 AND fur.usr_id = ' . $this->db->quote($this->user->getId(), 'integer') . '
644
645 LEFT JOIN usr_data ud
646 ON ud.usr_id = fp.pos_display_user_id
647
648 WHERE fpt.thr_fk = ' . $this->db->quote($this->id, 'integer');
649
650 if ($data) {
651 $query .= ' AND fpt.lft > ' . $this->db->quote($data['lft'], 'integer') .
652 ' AND fpt.lft < ' . $this->db->quote($data['rgt'], 'integer') . ' ';
653 }
654 if ($is_post_activation_enabled && !$this->is_moderator) {
655 $query .= ' AND (fp.pos_status = 1 OR fp.pos_status = 0 AND fp.pos_display_user_id = ' . $this->db->quote(
656 $this->user->getId(),
657 'integer'
658 ) . ') ';
659 }
660
661 if ($data && is_numeric($num_levels)) {
662 $query .= ' AND fpt.depth <= ' . $this->db->quote((int) $data['depth'] + $num_levels, 'integer') . ' ';
663 }
664
665 $query .= ' GROUP BY fpt.depth,
666 fpt.rgt,
667 fpt.parent_pos,
668 fp.pos_pk,
669 fp.pos_subject,
670 fp.pos_usr_alias,
671 fp.pos_date,
672 fp.pos_update,
673 fp.pos_status,
674 fp.pos_display_user_id,
675 fp.pos_usr_alias,
676 fp.import_name,
677 fp.pos_author_id,
678 fp.is_author_moderator,
679 fur.post_id
680 ORDER BY fpt.rgt DESC
681 ';
682
683 $queryCounter = '
684 SELECT pos_fk
685 FROM frm_posts_tree fpt
686 INNER JOIN frm_posts fp
687 ON fp.pos_pk = fpt.pos_fk
688 WHERE fpt.thr_fk = ' . $this->db->quote($this->id, 'integer');
689
690 if ($is_post_activation_enabled && !$this->is_moderator) {
691 $queryCounter .= ' AND (fp.pos_status = 1 OR fp.pos_status = 0 AND fp.pos_display_user_id = ' . $this->db->quote(
692 $this->user->getId(),
693 'integer'
694 ) . ') ';
695 }
696 $queryCounter .= ' ORDER BY fpt.rgt DESC';
697
698 $resCounter = $this->db->query($queryCounter);
699 $counter = [];
700 $i = 0;
701 while ($row = $this->db->fetchAssoc($resCounter)) {
702 $counter[(int) $row['pos_fk']] = $i++;
703 }
704
705 $res = $this->db->query($query);
706 $children = [];
707 $usr_ids = [];
708 while ($row = $this->db->fetchAssoc($res)) {
709 if ((int) $row['pos_display_user_id'] !== 0) {
710 $usr_ids[] = (int) $row['pos_display_user_id'];
711 }
712
713 $row['counter'] = $counter[$row['pos_pk']];
714 $casted_row = [];
715 $casted_row['depth'] = (int) $row['depth'];
716 $casted_row['rgt'] = (int) $row['rgt'];
717 $casted_row['parent_pos'] = (int) $row['parent_pos'];
718 $casted_row['pos_pk'] = (int) $row['pos_pk'];
719 $casted_row['pos_subject'] = (string) $row['pos_subject'];
720 $casted_row['pos_usr_alias'] = (string) $row['pos_usr_alias'];
721 $casted_row['pos_date'] = (string) $row['pos_date'];
722 $casted_row['pos_update'] = (string) $row['pos_update'];
723 $casted_row['pos_status'] = (int) $row['pos_status'];
724 $casted_row['pos_display_user_id'] = (int) $row['pos_display_user_id'];
725 $casted_row['import_name'] = (string) $row['import_name'];
726 $casted_row['pos_author_id'] = (int) $row['pos_author_id'];
727 $casted_row['is_author_moderator'] = (int) $row['is_author_moderator'];
728 $casted_row['post_id'] = (int) $row['post_id'];
729 $casted_row['post_read'] = (int) $row['post_read'];
730 $casted_row['children'] = (int) $row['children'];
731
732 $children[] = $casted_row;
733 }
734
736
737 return $children;
738 }
739
740 public function isNotificationEnabled(int $a_user_id): bool
741 {
742 if ($this->id && $a_user_id) {
743 $result = $this->db->queryF(
744 'SELECT COUNT(notification_id) cnt FROM frm_notification WHERE user_id = %s AND thread_id = %s',
745 ['integer', 'integer'],
746 [$a_user_id, $this->id]
747 );
748
749 if ($row = $this->db->fetchAssoc($result)) {
750 return (int) $row['cnt'] > 0;
751 }
752
753 return false;
754 }
755
756 return false;
757 }
758
759 public function enableNotification(int $a_user_id): void
760 {
761 if ($this->id && $a_user_id && !$this->isNotificationEnabled($a_user_id)) {
762 $nextId = $this->db->nextId('frm_notification');
763 $this->db->manipulateF(
764 '
765 INSERT INTO frm_notification
766 ( notification_id,
767 user_id,
768 thread_id
769 )
770 VALUES(%s, %s, %s)',
771 ['integer', 'integer', 'integer'],
772 [$nextId, $a_user_id, $this->id]
773 );
774 }
775 }
776
777 public function disableNotification(int $a_user_id): void
778 {
779 if ($this->id && $a_user_id) {
780 $this->db->manipulateF(
781 'DELETE FROM frm_notification WHERE user_id = %s AND thread_id = %s',
782 ['integer', 'integer'],
783 [$a_user_id, $this->id]
784 );
785 }
786 }
787
788 public function makeSticky(): bool
789 {
790 if ($this->id && !$this->is_sticky) {
791 $this->db->manipulateF(
792 'UPDATE frm_threads SET is_sticky = %s WHERE thr_pk = %s',
793 ['integer', 'integer'],
794 [1, $this->id]
795 );
796
797 $this->is_sticky = true;
798 return true;
799 }
800
801 return false;
802 }
803
804 public function unmakeSticky(): bool
805 {
806 if ($this->id && $this->is_sticky) {
807 $this->db->manipulateF(
808 'UPDATE frm_threads SET is_sticky = %s WHERE thr_pk = %s',
809 ['integer', 'integer'],
810 [0, $this->id]
811 );
812
813 $this->is_sticky = false;
814 return true;
815 }
816
817 return false;
818 }
819
820 public function close(): void
821 {
822 if ($this->id && !$this->is_closed) {
823 $this->db->manipulateF(
824 'UPDATE frm_threads SET is_closed = %s WHERE thr_pk = %s',
825 ['integer', 'integer'],
826 [1, $this->id]
827 );
828 $this->is_closed = true;
829 }
830 }
831
832 public function reopen(): void
833 {
834 if ($this->id && $this->is_closed) {
835 $this->db->manipulateF(
836 'UPDATE frm_threads SET is_closed = %s WHERE thr_pk = %s',
837 ['integer', 'integer'],
838 [0, $this->id]
839 );
840
841 $this->is_closed = false;
842 }
843 }
844
845 public function getAverageRating(): float
846 {
848 }
849
850 public function setAverageRating(float $average_rating): void
851 {
852 $this->average_rating = $average_rating;
853 }
854
855 public function setId(int $a_id): void
856 {
857 $this->id = $a_id;
858 }
859
860 public function getId(): int
861 {
862 return $this->id;
863 }
864
865 public function setForumId(int $a_forum_id): void
866 {
867 $this->forum_id = $a_forum_id;
868 }
869
870 public function getForumId(): int
871 {
872 return $this->forum_id;
873 }
874
875 public function setDisplayUserId(int $a_user_id): void
876 {
877 $this->display_user_id = $a_user_id;
878 }
879
880 public function getDisplayUserId(): int
881 {
883 }
884
885 public function setUserAlias(?string $a_user_alias): void
886 {
887 $this->user_alias = $a_user_alias;
888 }
889
890 public function getUserAlias(): ?string
891 {
892 return $this->user_alias;
893 }
894
895 public function setSubject(string $a_subject): void
896 {
897 $this->subject = $a_subject;
898 }
899
900 public function getSubject(): string
901 {
902 return $this->subject;
903 }
904
905 public function setCreateDate(?string $a_createdate): void
906 {
907 $this->createdate = $a_createdate;
908 }
909
910 public function getCreateDate(): ?string
911 {
912 return $this->createdate;
913 }
914
915 public function setChangeDate(?string $a_changedate): void
916 {
917 $this->changedate = $a_changedate;
918 }
919
920 public function getChangeDate(): ?string
921 {
922 return $this->changedate;
923 }
924
925 public function setImportName(?string $a_import_name): void
926 {
927 $this->import_name = $a_import_name;
928 }
929
930 public function getImportName(): ?string
931 {
932 return $this->import_name;
933 }
934
935 public function setLastPostString(?string $a_last_post): void
936 {
937 $this->last_post_string = $a_last_post;
938 }
939
940 public function getLastPostString(): ?string
941 {
943 }
944
945 public function setVisits(int $a_visits): void
946 {
947 $this->visits = $a_visits;
948 }
949
950 public function getVisits(): int
951 {
952 return $this->visits;
953 }
954
955 public function setSticky(bool $a_sticky): void
956 {
957 $this->is_sticky = $a_sticky;
958 }
959
960 public function isSticky(): bool
961 {
962 return $this->is_sticky;
963 }
964
965 public function setClosed(bool $a_closed): void
966 {
967 $this->is_closed = $a_closed;
968 }
969
970 public function isClosed(): bool
971 {
972 return $this->is_closed;
973 }
974
975 public function setOrderField(string $a_order_field): void
976 {
977 $this->orderField = $a_order_field;
978 }
979
980 public function getOrderField(): string
981 {
982 return $this->orderField;
983 }
984
985 public function getFrmObjId(): int
986 {
987 return $this->frm_obj_id;
988 }
989
990 public function setThrAuthorId(int $thr_author_id): void
991 {
992 $this->thr_author_id = $thr_author_id;
993 }
994
995 public function getThrAuthorId(): int
996 {
998 }
999
1000 public static function lookupTitle(int $a_topic_id): string
1001 {
1002 global $DIC;
1003 $ilDB = $DIC->database();
1004
1005 $res = $ilDB->queryF(
1006 'SELECT thr_subject FROM frm_threads WHERE thr_pk = %s',
1007 ['integer'],
1008 [$a_topic_id]
1009 );
1010
1011 if ($row = $ilDB->fetchObject($res)) {
1012 return (string) $row->thr_subject;
1013 }
1014
1015 return '';
1016 }
1017
1018 public function updateThreadTitle(): void
1019 {
1020 $this->db->update(
1021 'frm_threads',
1022 ['thr_subject' => ['text', $this->getSubject()]],
1023 ['thr_pk' => ['integer', $this->getId()]]
1024 );
1025
1026 try {
1027 $first_node = $this->getFirstVisiblePostNode();
1028 $first_node->setSubject($this->getSubject());
1029 $first_node->update();
1030 } catch (OutOfBoundsException) {
1031 }
1032 }
1033
1034 public function setNumPosts(int $a_num_posts): ilForumTopic
1035 {
1036 $this->num_posts = $a_num_posts;
1037 return $this;
1038 }
1039
1040 public function getNumPosts(): int
1041 {
1042 return $this->num_posts;
1043 }
1044
1046 {
1047 $this->num_unread_posts = $num_unread_posts;
1048 return $this;
1049 }
1050
1051 public function getNumUnreadPosts(): int
1052 {
1054 }
1055
1056 public function setUserNotificationEnabled(bool $status): ilForumTopic
1057 {
1058 $this->user_notification_enabled = $status;
1059 return $this;
1060 }
1061
1062 public function isUserNotificationEnabled(): bool
1063 {
1065 }
1066
1067 public function setOrderDirection(string $direction): ilForumTopic
1068 {
1069 if (!in_array(strtoupper($direction), self::$possibleOrderDirections, true)) {
1070 $direction = current(self::$possibleOrderDirections);
1071 }
1072
1073 $this->orderDirection = $direction;
1074 return $this;
1075 }
1076
1077 public function getOrderDirection(): string
1078 {
1079 return $this->orderDirection;
1080 }
1081
1082 public static function lookupForumIdByTopicId(int $a_topic_id): int
1083 {
1084 global $DIC;
1085 $ilDB = $DIC->database();
1086
1087 $res = $ilDB->queryF(
1088 'SELECT thr_top_fk FROM frm_threads WHERE thr_pk = %s',
1089 ['integer'],
1090 [$a_topic_id]
1091 );
1092
1093 $row = $ilDB->fetchAssoc($res);
1094
1095 return (int) $row['thr_top_fk'];
1096 }
1097
1098 public function updateMergedThread(): void
1099 {
1100 $this->db->update(
1101 'frm_threads',
1102 [
1103 'thr_num_posts' => ['integer', $this->getNumPosts()],
1104 'visits' => ['integer', $this->getVisits()],
1105 'thr_last_post' => ['text', $this->getLastPostString()],
1106 'thr_subject' => ['text', $this->getSubject()]
1107 ],
1108 ['thr_pk' => ['integer', $this->getId()]]
1109 );
1110 }
1111
1112 public static function lookupCreationDate(int $thread_id): ?string
1113 {
1114 global $DIC;
1115 $ilDB = $DIC->database();
1116
1117 $res = $ilDB->queryF(
1118 'SELECT thr_date FROM frm_threads WHERE thr_pk = %s',
1119 ['integer'],
1120 [$thread_id]
1121 );
1122
1123 $date = null;
1124 $row = $ilDB->fetchAssoc($res);
1125 if (is_array($row)) {
1126 $date = $row['thr_date'];
1127 }
1128
1129 return $date;
1130 }
1131
1133 {
1134 return $this->last_post;
1135 }
1136
1138 {
1139 $this->last_post = $post;
1140 }
1141}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstance(int $a_obj_id=0)
setDisplayUserId(int $a_user_id)
isNotificationEnabled(int $a_user_id)
static lookupTitle(int $a_topic_id)
countPosts(bool $ignoreRoot=false)
ilForumPost $last_post
disableNotification(int $a_user_id)
enableNotification(int $a_user_id)
setLastPostString(?string $a_last_post)
setSticky(bool $a_sticky)
assignData(array $data)
getPostTree(ilForumPost $a_post_node)
Fetches and returns an array of posts from the post tree, starting with the node object passed by the...
__construct(private int $id=0, private readonly bool $is_moderator=false, bool $preventImplicitRead=false)
Returns an object of a forum topic.
static array $possibleOrderDirections
countActivePosts(bool $ignoreRoot=false)
getFirstVisiblePostNode(bool $isModerator=false, bool $preventImplicitRead=false)
setChangeDate(?string $a_changedate)
readonly ilObjUser $user
setNumUnreadPosts(int $num_unread_posts)
setAverageRating(float $average_rating)
setClosed(bool $a_closed)
setUserAlias(?string $a_user_alias)
setCreateDate(?string $a_createdate)
getPostRootNode(bool $isModerator=false, bool $preventImplicitRead=false)
static lookupCreationDate(int $thread_id)
setOrderDirection(string $direction)
readonly ilDBInterface $db
bool $user_notification_enabled
setThrAuthorId(int $thr_author_id)
setSubject(string $a_subject)
static lookupForumIdByTopicId(int $a_topic_id)
movePosts(int $old_obj_id, int $old_pk, int $new_obj_id, int $new_pk)
Moves all posts within the current thread to a new forum.
getNestedSetPostChildren(?int $pos_id=null, ?int $num_levels=null)
setImportName(?string $a_import_name)
setForumId(int $a_forum_id)
setUserNotificationEnabled(bool $status)
setVisits(int $a_visits)
setOrderField(string $a_order_field)
setNumPosts(int $a_num_posts)
setLastPostForThreadOverview(ilForumPost $post)
static _lookupObjIdForForumId(int $a_for_id)
A news item can be created by different sources.
static getFirstNewsIdForContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Get first new id of news set related to a certain context.
User class.
static get(string $a_var)
static set(string $a_var, $a_val)
Set a value.
const ANONYMOUS_USER_ID
Definition: constants.php:27
Interface ilDBInterface.
$res
Definition: ltiservices.php:69
$post
Definition: ltitoken.php:46
global $DIC
Definition: shib_login.php:26
$counter