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