19 declare(strict_types=1);
61 private readonly
bool $is_moderator =
false,
62 bool $preventImplicitRead =
false 65 $this->db = $DIC->database();
66 $this->
user = $DIC->user();
68 if (!$preventImplicitRead) {
75 $this->
setId((
int) $data[
'thr_pk']);
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);
91 if (isset($data[
'num_posts'])) {
94 if (isset($data[
'num_unread_posts'])) {
97 if (isset($data[
'usr_notification_is_enabled'])) {
104 if ($this->forum_id !== 0) {
105 $nextId = $this->db->nextId(
'frm_threads');
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]
137 if ($this->
id !== 0) {
138 $this->db->manipulateF(
148 [
'integer',
'text',
'timestamp',
'integer',
'text',
'text',
'integer'],
154 $this->last_post_string,
155 (
string) $this->average_rating,
168 if ($this->
id !== 0) {
169 $res = $this->db->queryF(
171 SELECT frm_threads.*, top_frm_fk frm_obj_id 173 INNER JOIN frm_data ON top_pk = thr_top_fk 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;
209 return $this->
read();
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'],
221 if (($row = $this->db->fetchObject(
$res)) !==
null) {
222 return (
int) $row->pos_fk ?: 0;
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'],
236 if (($row = $this->db->fetchObject(
$res)) !==
null) {
237 return (
int) $row->pos_fk ?: 0;
244 $checkTime = time() - (60 * 60);
246 if (
ilSession::get(
'frm_visit_frm_threads_' . $this->
id) < $checkTime) {
249 $this->db->manipulateF(
250 'UPDATE frm_threads SET visits = visits + 1 WHERE thr_pk = %s',
259 $res = $this->db->queryF(
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 ' :
''),
269 $row = $this->db->fetchAssoc(
$res);
270 if (is_array($row)) {
271 return (
int) $row[
'cnt'];
279 $res = $this->db->queryF(
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'],
291 $row = $this->db->fetchAssoc(
$res);
292 if (is_array($row)) {
293 return (
int) $row[
'cnt'];
301 $this->db->setLimit(1);
302 $res = $this->db->queryF(
306 INNER JOIN frm_posts_tree ON pos_fk = pos_pk 307 WHERE parent_pos = %s 310 [
'integer',
'integer'],
314 if ($row = $this->db->fetchAssoc(
$res)) {
315 $post =
new ilForumPost((
int) $row[
'pos_pk'], $isModerator, $preventImplicitRead);
316 $post->assignData($row);
325 $this->db->setLimit(1);
326 $res = $this->db->queryF(
330 INNER JOIN frm_posts_tree ON pos_fk = pos_pk 331 WHERE parent_pos != %s 335 [
'integer',
'integer',
'integer'],
339 if ($row = $this->db->fetchAssoc(
$res)) {
340 $post =
new ilForumPost((
int) $row[
'pos_pk'], $isModerator, $preventImplicitRead);
341 $post->assignData($row);
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',
358 if (($row = $this->db->fetchObject(
$res)) !==
null) {
368 if ($this->
id !== 0) {
369 $this->db->setLimit(1);
370 $res = $this->db->queryF(
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()]
381 if (($row = $this->db->fetchObject(
$res)) !==
null) {
386 throw new OutOfBoundsException(sprintf(
'Could not find last active posting by id: %s', $this->
id));
396 if ($this->
id !== 0) {
397 $res = $this->db->queryF(
'SELECT pos_pk FROM frm_posts WHERE pos_thr_fk = %s', [
'integer'], [$this->
id]);
400 $posts[(
int) $row->pos_pk] = (
int) $row->pos_pk;
419 if ($a_post_node->
getLft() > 1) {
420 $dummy_root_condition =
'lft >= %s AND lft < %s';
422 $dummy_root_condition =
'lft > %s AND lft < %s';
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, 432 WHEN fur.post_id IS NULL ' .
437 firstname, lastname, title, login 445 ON pos_display_user_id = usr_id 447 LEFT JOIN frm_user_read fur 448 ON fur.thread_id = pos_thr_fk 449 AND fur.post_id = pos_pk 452 WHERE ' . $dummy_root_condition .
' 454 $data_types[] =
'integer';
455 $data_types[] =
'integer';
456 $data_types[] =
'integer';
457 $data_types[] =
'integer';
463 if ($this->orderField !==
'') {
467 $res = $this->db->queryF($query, $data_types,
$data);
470 while ($row = $this->db->fetchAssoc(
$res)) {
472 $post->assignData($row);
474 if (!$this->is_moderator && !
$post->isActivated() &&
$post->getPosAuthorId() !== $this->
user->getId()) {
478 if ((
int) $row[
'pos_display_user_id'] !== 0) {
479 $usr_ids[(
int) $row[
'pos_display_user_id']] = (
int) $row[
'pos_display_user_id'];
481 if ((
int) $row[
'update_user'] !== 0) {
482 $usr_ids[(
int) $row[
'update_user']] = (
int) $row[
'update_user'];
502 public function movePosts(
int $old_obj_id,
int $old_pk,
int $new_obj_id,
int $new_pk):
int 504 if ($this->
id === 0) {
511 foreach ($post_ids as $post_id) {
513 $moved = $file_obj->moveFilesOfPost($new_obj_id);
517 'from' => $old_obj_id,
519 'position_id' => $post_id
526 foreach ($postsMoved as $postedInformation) {
527 $file_obj =
new ilFileDataForum($postedInformation[
'to'], $postedInformation[
'position_id']);
528 $file_obj->moveFilesOfPost($postedInformation[
'from']);
536 $ilAtomQuery = $this->db->buildAtomQuery();
537 $ilAtomQuery->addTableLock(
'frm_user_read');
539 $ilAtomQuery->addQueryCallable(
static function (
ilDBInterface $ilDB) use ($new_obj_id, $current_id):
void {
541 'DELETE FROM frm_user_read WHERE obj_id = %s AND thread_id =%s',
542 [
'integer',
'integer'],
543 [$new_obj_id, $current_id]
547 'UPDATE frm_user_read SET obj_id = %s WHERE thread_id = %s',
548 [
'integer',
'integer'],
549 [$new_obj_id, $current_id]
555 $this->db->manipulateF(
556 'UPDATE frm_posts SET pos_top_fk = %s WHERE pos_thr_fk = %s',
557 [
'integer',
'integer'],
561 $res = $this->db->queryF(
562 'SELECT * FROM frm_posts WHERE pos_thr_fk = %s',
570 while (
$post = $this->db->fetchAssoc(
$res)) {
574 (
int)
$post[
'pos_pk'],
578 $news_item->setContextObjId($new_obj_id);
579 $news_item->update();
582 return count($post_ids);
589 $is_post_activation_enabled = $objProperties->isPostActivationEnabled();
591 if ($pos_id !==
null) {
592 $res = $this->db->queryF(
594 SELECT lft, rgt, depth 598 [
'integer',
'integer'],
615 fp.pos_display_user_id, 619 fp.is_author_moderator, 622 WHEN fur.post_id IS NULL ' .
627 COUNT(fpt2.pos_fk) children 629 FROM frm_posts_tree fpt 631 INNER JOIN frm_posts fp 632 ON fp.pos_pk = fpt.pos_fk 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 ';
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') .
' 645 LEFT JOIN usr_data ud 646 ON ud.usr_id = fp.pos_display_user_id 648 WHERE fpt.thr_fk = ' . $this->db->quote($this->id,
'integer');
651 $query .=
' AND fpt.lft > ' . $this->db->quote(
$data[
'lft'],
'integer') .
652 ' AND fpt.lft < ' . $this->db->quote(
$data[
'rgt'],
'integer') .
' ';
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(),
661 if (
$data && is_numeric($num_levels)) {
662 $query .=
' AND fpt.depth <= ' . $this->db->quote((
int)
$data[
'depth'] + $num_levels,
'integer') .
' ';
665 $query .=
' GROUP BY fpt.depth, 674 fp.pos_display_user_id, 678 fp.is_author_moderator, 680 ORDER BY fpt.rgt DESC 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');
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(),
696 $queryCounter .=
' ORDER BY fpt.rgt DESC';
698 $resCounter = $this->db->query($queryCounter);
701 while ($row = $this->db->fetchAssoc($resCounter)) {
702 $counter[(
int) $row[
'pos_fk']] = $i++;
705 $res = $this->db->query($query);
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'];
713 $row[
'counter'] = $counter[$row[
'pos_pk']];
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'];
732 $children[] = $casted_row;
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]
749 if ($row = $this->db->fetchAssoc($result)) {
750 return (
int) $row[
'cnt'] > 0;
762 $nextId = $this->db->nextId(
'frm_notification');
763 $this->db->manipulateF(
765 INSERT INTO frm_notification 771 [
'integer',
'integer',
'integer'],
772 [$nextId, $a_user_id, $this->
id]
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]
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'],
797 $this->is_sticky =
true;
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'],
813 $this->is_sticky =
false;
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'],
828 $this->is_closed =
true;
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'],
841 $this->is_closed =
false;
855 public function setId(
int $a_id): void
867 $this->forum_id = $a_forum_id;
877 $this->display_user_id = $a_user_id;
887 $this->user_alias = $a_user_alias;
897 $this->subject = $a_subject;
907 $this->createdate = $a_createdate;
917 $this->changedate = $a_changedate;
927 $this->import_name = $a_import_name;
937 $this->last_post_string = $a_last_post;
947 $this->visits = $a_visits;
957 $this->is_sticky = $a_sticky;
967 $this->is_closed = $a_closed;
977 $this->orderField = $a_order_field;
1003 $ilDB = $DIC->database();
1006 'SELECT thr_subject FROM frm_threads WHERE thr_pk = %s',
1012 return (
string) $row->thr_subject;
1022 [
'thr_subject' => [
'text', $this->
getSubject()]],
1023 [
'thr_pk' => [
'integer', $this->
getId()]]
1028 $first_node->setSubject($this->
getSubject());
1029 $first_node->update();
1036 $this->num_posts = $a_num_posts;
1058 $this->user_notification_enabled = $status;
1069 if (!in_array(strtoupper($direction), self::$possibleOrderDirections,
true)) {
1070 $direction = current(self::$possibleOrderDirections);
1073 $this->orderDirection = $direction;
1085 $ilDB = $DIC->database();
1088 'SELECT thr_top_fk FROM frm_threads WHERE thr_pk = %s',
1095 return (
int) $row[
'thr_top_fk'];
1103 'thr_num_posts' => [
'integer', $this->
getNumPosts()],
1104 'visits' => [
'integer', $this->
getVisits()],
1106 'thr_subject' => [
'text', $this->
getSubject()]
1108 [
'thr_pk' => [
'integer', $this->
getId()]]
1115 $ilDB = $DIC->database();
1118 'SELECT thr_date FROM frm_threads WHERE thr_pk = %s',
1125 if (is_array($row)) {
1126 $date = $row[
'thr_date'];
1139 $this->last_post =
$post;
static get(string $a_var)
readonly ilDBInterface $db
manipulateF(string $query, array $types, array $values)
getNestedSetPostChildren(?int $pos_id=null, ?int $num_levels=null)
setCreateDate(?string $a_createdate)
static array $possibleOrderDirections
setUserAlias(?string $a_user_alias)
setDisplayUserId(int $a_user_id)
static lookupTitle(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.
enableNotification(int $a_user_id)
setLastPostString(?string $a_last_post)
setSticky(bool $a_sticky)
static lookupCreationDate(int $thread_id)
setNumPosts(int $a_num_posts)
getPostRootNode(bool $isModerator=false, bool $preventImplicitRead=false)
static getInstance(int $a_obj_id=0)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
setImportName(?string $a_import_name)
countActivePosts(bool $ignoreRoot=false)
setForumId(int $a_forum_id)
getLastPostForThreadOverview()
setNumUnreadPosts(int $num_unread_posts)
setAverageRating(float $average_rating)
setClosed(bool $a_closed)
static _lookupObjIdForForumId(int $a_for_id)
isUserNotificationEnabled()
setChangeDate(?string $a_changedate)
A news item can be created by different sources.
setSubject(string $a_subject)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
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.
setLastPostForThreadOverview(ilForumPost $post)
setOrderField(string $a_order_field)
setUserNotificationEnabled(bool $status)
static lookupForumIdByTopicId(int $a_topic_id)
__construct(private int $id=0, private readonly bool $is_moderator=false, bool $preventImplicitRead=false)
Returns an object of a forum topic.
getPostTree(ilForumPost $a_post_node)
Fetches and returns an array of posts from the post tree, starting with the node object passed by the...
isNotificationEnabled(int $a_user_id)
disableNotification(int $a_user_id)
getFirstVisiblePostNode(bool $isModerator=false, bool $preventImplicitRead=false)
countPosts(bool $ignoreRoot=false)
static set(string $a_var, $a_val)
Set a value.
setOrderDirection(string $direction)
bool $user_notification_enabled
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setThrAuthorId(int $thr_author_id)