19 declare(strict_types=1);
44 private string $replQuote1 =
'<blockquote class="ilForumQuote">';
60 $this->error = $DIC[
'ilErr'];
61 $this->
lng = $DIC->language();
62 $this->db = $DIC->database();
63 $this->
user = $DIC->user();
65 $this->
event = $DIC->event();
70 $this->
id = $a_obj_id;
75 $this->ref_id = $a_ref_id;
90 if ($dbTable ===
'') {
91 die($this->className .
'::setDbTable(): No database table given.');
104 $this->mdb2Query = $query_string;
105 $this->mdb2DataValue = $data_value;
106 $this->mdb2DataType = $data_type;
113 return $this->mdb2Query ?:
'';
118 return $this->mdb2DataValue ?: [];
123 return $this->mdb2DataType ?: [];
146 $query =
'SELECT * FROM frm_data WHERE ';
155 $res = $this->db->queryF($query, $data_type, $data_value);
156 $row = $this->db->fetchAssoc(
$res);
158 if (!is_array($row) || $row === []) {
170 $query =
'SELECT * FROM frm_threads WHERE ';
179 $sql_res = $this->db->queryF($query, $data_type, $data_value);
180 $result = $this->db->fetchAssoc($sql_res);
181 $result[
'thr_subject'] = trim((
string) ($result[
'thr_subject'] ??
''));
184 $thread_obj->assignData($result);
189 public function generatePost(
193 int $display_user_id,
197 string $subject =
'',
198 ?
string $alias = null,
201 bool $send_activation_mail =
false 204 $objNewPost->setForumId($forum_id);
205 $objNewPost->setThreadId($thread_id);
206 $objNewPost->setSubject($subject);
207 $objNewPost->setMessage($message);
208 $objNewPost->setDisplayUserId($display_user_id);
209 $objNewPost->setUserAlias($alias);
210 $objNewPost->setPosAuthorId($author_id);
214 $is_moderator =
false;
215 if ($frm_settings->getMarkModeratorPosts() && self::_isModerator($this->
getForumRefId(), $author_id)) {
216 $is_moderator =
true;
218 $objNewPost->setIsAuthorModerator($is_moderator);
221 $objNewPost->setCreateDate(date(
'Y-m-d H:i:s'));
222 } elseif (strpos($date,
'-') > 0) {
223 $objNewPost->setCreateDate($date);
227 $objNewPost->setPostActivationDate($objNewPost->getCreateDate());
231 $objNewPost->setNotification($notify);
232 $objNewPost->setStatus($status);
233 $objNewPost->insert();
235 if ($parent_pos === 0) {
236 $this->
addPostTree($objNewPost->getThreadId(), $objNewPost->getId(), $objNewPost->getCreateDate());
239 $objNewPost->getId(),
241 $objNewPost->getThreadId(),
242 $objNewPost->getCreateDate()
246 $lastPost = $objNewPost->getForumId() .
'#' . $objNewPost->getThreadId() .
'#' . $objNewPost->getId();
248 $this->db->manipulateF(
249 'UPDATE frm_threads SET thr_num_posts = thr_num_posts + 1, thr_last_post = %s WHERE thr_pk = %s',
251 [$lastPost, $objNewPost->getThreadId()]
254 $this->db->manipulateF(
255 'UPDATE frm_data SET top_num_posts = top_num_posts + 1, top_last_post = %s WHERE top_pk = %s',
257 [$lastPost, $objNewPost->getForumId()]
262 $forum_obj->markPostRead($objNewPost->getPosAuthorId(), $objNewPost->getThreadId(), $objNewPost->getId());
264 if ($status && $parent_pos > 0) {
266 $news_item->setContext($forum_obj->getId(),
'frm', $objNewPost->getId(),
'pos');
268 $news_item->setTitle($objNewPost->getSubject());
273 if ($objNewPost->getMessage() !== strip_tags($objNewPost->getMessage())) {
274 $news_item->setContentHtml(
true);
277 $news_item->setUserId($display_user_id);
279 $news_item->create();
282 return $objNewPost->getId();
291 bool $withFirstVisibleEntry =
true 304 $this->db->manipulateF(
305 'UPDATE frm_data SET top_num_threads = top_num_threads + 1 WHERE top_pk = %s',
310 $rootNodeId = $this->generatePost(
325 if (!$withFirstVisibleEntry) {
329 return $this->generatePost(
353 if ($target_obj_id <= 0 || $src_forum->
getId() <= 0) {
354 return $errorMessages;
363 if (!$oldFrmData->getTopPk() || !$newFrmData->getTopPk()) {
364 return $errorMessages;
367 $num_moved_posts = 0;
368 $num_moved_threads = 0;
371 foreach ($thread_ids as $id) {
375 $numPosts = $objTmpThread->movePosts(
377 $oldFrmData->getTopPk(),
379 $newFrmData->getTopPk()
382 if (($last_post_string = $objTmpThread->getLastPostString()) !==
'') {
383 $last_post_string = explode(
'#', $last_post_string);
384 $last_post_string[0] = $newFrmData->getTopPk();
385 $last_post_string = implode(
'#', $last_post_string);
386 $objTmpThread->setLastPostString($last_post_string);
389 $num_visits += $objTmpThread->getVisits();
390 $num_moved_posts += $numPosts;
391 ++$num_moved_threads;
393 $objTmpThread->setForumId($newFrmData->getTopPk());
394 $objTmpThread->update();
396 $errorMessages[] = sprintf($this->
lng->txt(
'frm_move_invalid_file_type'), $objTmpThread->getSubject());
401 if (0 === max($num_moved_threads, $num_moved_posts, $num_visits)) {
402 return $errorMessages;
405 $this->db->setLimit(1, 0);
406 $res = $this->db->queryF(
407 'SELECT pos_thr_fk, pos_pk FROM frm_posts WHERE pos_top_fk = %s ORDER BY pos_date DESC',
409 [$oldFrmData->getTopPk()]
413 $row = $this->db->fetchObject(
$res);
415 $last_post_src = $oldFrmData->getTopPk() .
'#' . $row->pos_thr_fk .
'#' . $row->pos_pk;
418 $this->db->manipulateF(
420 'SET top_num_posts = top_num_posts - %s, top_num_threads = top_num_threads - %s, visits = visits - %s, ' .
421 'top_last_post = %s WHERE top_pk = %s',
422 [
'integer',
'integer',
'integer',
'text',
'integer'],
428 $oldFrmData->getTopPk()
432 $this->db->setLimit(1, 0);
433 $res = $this->db->queryF(
434 'SELECT pos_thr_fk, pos_pk FROM frm_posts WHERE pos_top_fk = %s ORDER BY pos_date DESC',
436 [$newFrmData->getTopPk()]
439 $last_post_dest =
'';
440 $row = $this->db->fetchObject(
$res);
442 $last_post_dest = $newFrmData->getTopPk() .
'#' . $row->pos_thr_fk .
'#' . $row->pos_pk;
445 $this->db->manipulateF(
446 'UPDATE frm_data SET top_num_posts = top_num_posts + %s, top_num_threads = top_num_threads + %s, ' .
447 'visits = visits + %s, top_last_post = %s WHERE top_pk = %s',
448 [
'integer',
'integer',
'integer',
'text',
'integer'],
449 [$num_moved_posts, $num_moved_threads, $num_visits, $last_post_dest, $newFrmData->getTopPk()]
456 'source_ref_id' => $src_forum->
getId(),
457 'target_ref_id' => $src_forum->
getId(),
458 'thread_ids' => $src_forum->
getId(),
459 'source_frm_obj_id' => $src_forum->
getId(),
460 'target_frm_obj_id' => $target_obj_id
464 return $errorMessages;
469 $cens_date = date(
'Y-m-d H:i:s');
471 $this->db->manipulateF(
473 SET pos_cens_com = %s, 478 [
'text',
'timestamp',
'integer',
'integer',
'integer'],
482 $this->
user->getId(),
496 $news_item->setContent(nl2br($this->
prepareText($message, 0)));
497 $news_item->setContentHtml(
false);
498 if ($message !== strip_tags($message)) {
499 $news_item->setContentHtml(
true);
502 $res = $this->db->queryF(
'SELECT pos_message FROM frm_posts WHERE pos_pk = %s', [
'integer'], [$pos_pk]);
503 $rec = $this->db->fetchAssoc(
$res);
506 $news_item->setContent(nl2br($this->
prepareText($rec[
'pos_message'], 0)));
507 $news_item->setContentHtml(
false);
508 if ($rec[
'pos_message'] !== strip_tags($rec[
'pos_message'])) {
509 $news_item->setContentHtml(
true);
512 $news_item->update();
531 $p_node = $postIdOrRecord;
532 if (is_numeric($postIdOrRecord)) {
538 $is_deleted_thread = (
$post->getParentId() == 0) ?
true :
false;
539 $num_visible_active_posts = 0;
540 if ($is_deleted_thread) {
542 SELECT COUNT(*) AS cnt 544 INNER JOIN frm_posts_tree ON pos_pk = pos_fk 545 WHERE frm_posts_tree.parent_pos != 0 546 AND pos_thr_fk = ' . $this->db->quote(
$post->getThreadId(),
'integer') .
' 547 AND pos_status = ' . $this->db->quote(1,
'integer');
548 $res = $this->db->query($query);
549 $row = $this->db->fetchAssoc(
$res);
550 $num_visible_active_posts = (
int) ($row[
'cnt'] ?? 0);
555 'beforePostDeletion',
560 'thread_deleted' => $is_deleted_thread,
561 'num_visible_active_posts' => $num_visible_active_posts
571 $affected_user_ids[] =
$post->getPosAuthorId();
575 $obj_history->deleteHistoryByPostIds($deleted_post_ids);
578 $obj_draft->deleteDraftsByPostIds($deleted_post_ids);
580 foreach ($deleted_post_ids as $post_id) {
584 $dead_pos = count($deleted_post_ids);
587 if ((
int)
$post->getParentId() === 0) {
588 $dead_thr =
$post->getThreadId();
590 $this->db->manipulateF(
'DELETE FROM frm_threads WHERE thr_pk = %s', [
'integer'], [$dead_thr]);
591 $this->db->manipulateF(
592 'UPDATE frm_data SET top_num_threads = top_num_threads - 1 WHERE top_frm_fk = %s',
597 $posset = $this->db->queryF(
'SELECT * FROM frm_posts WHERE pos_thr_fk = %s', [
'integer'], [$dead_thr]);
598 while ($posrec = $this->db->fetchAssoc($posset)) {
602 (
int) $posrec[
'pos_pk'],
607 $news_item->delete();
612 foreach ($mobs as $mob) {
621 $affected_user_ids[] = (
int) $posrec[
'pos_author_id'];
624 $this->db->manipulateF(
'DELETE FROM frm_posts WHERE pos_thr_fk = %s', [
'integer'], [
$post->getThreadId()]);
626 for ($i = 0; $i < $dead_pos; $i++) {
627 $this->db->manipulateF(
'DELETE FROM frm_posts WHERE pos_pk = %s', [
'integer'], [$deleted_post_ids[$i]]);
632 $deleted_post_ids[$i],
637 $news_item->delete();
642 foreach ($mobs as $mob) {
653 $this->db->manipulateF(
654 'UPDATE frm_threads SET thr_num_posts = thr_num_posts - %s WHERE thr_pk = %s',
655 [
'integer',
'integer'],
656 [$dead_pos,
$post->getTreeId()]
659 $res1 = $this->db->queryF(
660 'SELECT * FROM frm_posts WHERE pos_thr_fk = %s ORDER BY pos_date DESC',
666 if ($res1->numRows() > 0) {
669 while ($selData = $this->db->fetchAssoc($res1)) {
674 $lastPost_thr = $selData[
'pos_top_fk'] .
'#' . $selData[
'pos_thr_fk'] .
'#' . $selData[
'pos_pk'];
679 $this->db->manipulateF(
680 'UPDATE frm_threads SET thr_last_post = %s WHERE thr_pk = %s',
682 [$lastPost_thr,
$post->getTreeId()]
686 $this->db->manipulateF(
687 'UPDATE frm_data SET top_num_posts = top_num_posts - %s WHERE top_frm_fk = %s',
688 [
'integer',
'integer'],
689 [$dead_pos, $this->
id]
692 $res2 = $this->db->queryF(
693 'SELECT * FROM frm_posts, frm_data WHERE pos_top_fk = top_pk AND top_frm_fk = %s ORDER BY pos_date DESC',
699 if ($res2->numRows() > 0) {
702 while ($selData = $this->db->fetchAssoc($res2)) {
707 $lastPost_top = $selData[
'pos_top_fk'] .
'#' . $selData[
'pos_thr_fk'] .
'#' . $selData[
'pos_pk'];
712 $this->db->manipulateF(
713 'UPDATE frm_data SET top_last_post = %s WHERE top_frm_fk = %s',
715 [$lastPost_top, $this->
id]
725 'user_ids' => $affected_user_ids
739 $is_post_activation_enabled = $frm_props->isPostActivationEnabled();
741 $user_id = $this->
user->getId();
743 $excluded_ids_condition =
'';
744 if (isset(
$params[
'excluded_ids']) && is_array(
$params[
'excluded_ids']) &&
$params[
'excluded_ids']) {
745 $excluded_ids_condition =
' AND ' . $this->db->in(
'thr_pk',
$params[
'excluded_ids'],
true,
'integer') .
' ';
748 if (!isset(
$params[
'order_column']) || !in_array(
749 strtolower(
$params[
'order_column']),
750 [
'lp_date',
'rating',
'thr_subject',
'num_posts',
'num_visit']
752 $params[
'order_column'] =
'post_date';
754 if (!isset(
$params[
'order_direction']) || !in_array(strtolower(
$params[
'order_direction']), [
'asc',
'desc'])) {
755 $params[
'order_direction'] =
'desc';
758 $cnt_active_pos_query =
'';
759 $cnt_join_type =
'LEFT';
760 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
761 $cnt_active_pos_query =
" AND (pos_status = {$this->db->quote(1, 'integer')} OR pos_author_id = {$this->db->quote($user_id, 'integer')}) ";
762 $cnt_join_type =
"INNER";
765 "SELECT COUNT(DISTINCT(thr_pk)) cnt 767 $cnt_join_type JOIN frm_posts 768 ON pos_thr_fk = thr_pk $cnt_active_pos_query 769 WHERE thr_top_fk = %s $excluded_ids_condition 771 $res = $this->db->queryF($query, [
'integer'], [$a_topic_id]);
772 $cntData = $this->db->fetchAssoc(
$res);
773 $cnt = (
int) $cntData[
'cnt'];
777 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
778 $active_query =
' AND (pos_status = %s OR pos_author_id = %s) ';
779 $having =
' HAVING num_posts > 0';
786 $optional_fields =
'';
787 if ($frm_props->isIsThreadRatingEnabled()) {
788 $optional_fields =
', avg_rating';
791 $additional_sort =
'';
793 if (
$params[
'order_column'] ===
'thr_subject') {
794 $dynamic_columns = [
', thr_subject ' .
$params[
'order_direction']];
795 } elseif (
$params[
'order_column'] ===
'num_posts') {
796 $dynamic_columns = [
', num_posts ' .
$params[
'order_direction']];
797 } elseif (
$params[
'order_column'] ===
'num_visit') {
798 $dynamic_columns = [
', visits ' .
$params[
'order_direction']];
800 $dynamic_columns = [
', post_date ' .
$params[
'order_direction']];
803 if ($frm_props->isIsThreadRatingEnabled()) {
804 $dynamic_columns[] =
' ,avg_rating ' .
$params[
'order_direction'];
806 if (
'rating' === strtolower(
$params[
'order_column'])) {
807 $dynamic_columns = array_reverse($dynamic_columns);
809 $additional_sort .= implode(
' ', $dynamic_columns);
812 if (!$this->
user->isAnonymous()) {
814 (CASE WHEN COUNT(DISTINCT(notification_id)) > 0 THEN 1 ELSE 0 END) usr_notification_is_enabled, 815 MAX(pos_date) post_date, 816 SUM(tree1.parent_pos != 0) num_posts, 817 SUM(tree1.parent_pos != 0) - SUM(tree1.parent_pos != 0 AND postread.post_id IS NOT NULL) num_unread_posts, ";
819 $query .=
" thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 823 LEFT JOIN frm_notification 824 ON frm_notification.thread_id = thr_pk 825 AND frm_notification.user_id = %s 828 ON pos_thr_fk = thr_pk $active_query 829 LEFT JOIN frm_posts_tree tree1 830 ON tree1.pos_fk = frm_posts.pos_pk 831 LEFT JOIN frm_user_read postread 832 ON postread.post_id = pos_pk 833 AND postread.usr_id = %s";
835 $query .=
" WHERE thr_top_fk = %s 836 $excluded_ids_condition 837 GROUP BY thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 840 ORDER BY is_sticky DESC $additional_sort, thr_date DESC";
843 $data_types[] =
'integer';
844 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
845 $data_types[] =
'integer';
846 $data_types[] =
'integer';
848 $data_types[] =
'integer';
849 $data_types[] =
'integer';
853 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
860 0 usr_notification_is_enabled, 861 MAX(pos_date) post_date, 862 COUNT(DISTINCT(tree1.pos_fk)) num_posts, 863 COUNT(DISTINCT(tree1.pos_fk)) num_unread_posts, 864 thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 869 ON pos_thr_fk = thr_pk $active_query 870 LEFT JOIN frm_posts_tree tree1 871 ON tree1.pos_fk = frm_posts.pos_pk AND tree1.parent_pos != 0 874 $query .=
" WHERE thr_top_fk = %s 875 $excluded_ids_condition 876 GROUP BY thr_pk, thr_top_fk, thr_subject, thr_author_id, thr_display_user_id, thr_usr_alias, thr_num_posts, thr_last_post, thr_date, thr_update, visits, frm_threads.import_name, is_sticky, is_closed 879 ORDER BY is_sticky DESC $additional_sort, thr_date DESC";
881 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
882 $data_types[] =
'integer';
883 $data_types[] =
'integer';
885 $data_types[] =
'integer';
886 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
891 $data[] = $a_topic_id;
893 if ($limit || $offset) {
894 $this->db->setLimit($limit, $offset);
898 $res = $this->db->queryF($query, $data_types,
$data);
899 while ($row = $this->db->fetchAssoc(
$res)) {
901 $thread->assignData($row);
902 $threads[(
int) $row[
'thr_pk']] = $thread;
903 $threadIds[] = (
int) $row[
'thr_pk'];
906 $inner_last_active_post_condition =
'';
907 if ($is_post_activation_enabled && !
$params[
'is_moderator']) {
908 $inner_last_active_post_condition = sprintf(
909 ' AND (iposts.pos_status = %s OR (iposts.pos_status = %s AND iposts.pos_author_id = %s)) ',
910 $this->db->quote(1,
'integer'),
911 $this->db->quote(0,
'integer'),
912 $this->db->quote($this->
user->getId(),
'integer')
916 $post_res = $this->db->query(
920 SELECT pos_thr_fk, MAX(iposts.pos_date) i_pos_date 921 FROM frm_posts iposts 922 WHERE ' . $this->db->in(
'iposts.pos_thr_fk', $threadIds,
false,
'integer') .
' 923 ' . $inner_last_active_post_condition .
' 925 ) opost ON frm_posts.pos_thr_fk = opost.pos_thr_fk AND frm_posts.pos_date = opost.i_pos_date' 927 while ($post_row = $this->db->fetchAssoc($post_res)) {
928 $tmp_obj =
new ilForumPost((
int) $post_row[
'pos_pk'], (
bool)
$params[
'is_moderator'],
true);
929 $tmp_obj->setPosAuthorId((
int) $post_row[
'pos_author_id']);
930 $tmp_obj->setDisplayUserId((
int) $post_row[
'pos_display_user_id']);
931 $tmp_obj->setUserAlias((
string) $post_row[
'pos_usr_alias']);
932 $tmp_obj->setImportName((
string) $post_row[
'import_name']);
933 $tmp_obj->setId((
int) $post_row[
'pos_pk']);
934 $tmp_obj->setCreateDate((
string) $post_row[
'pos_date']);
936 $threads[(
int) $post_row[
'pos_thr_fk']]->setLastPostForThreadOverview($tmp_obj);
949 SUM(IF(f.pos_cens = %s, 1, 0)) cnt 951 INNER JOIN frm_posts_tree t ON f.pos_pk = t.pos_fk AND t.parent_pos != %s 952 INNER JOIN frm_threads th ON t.thr_fk = th.thr_pk 953 INNER JOIN frm_data d ON d.top_pk = f.pos_top_fk AND d.top_frm_fk = %s 954 WHERE f.pos_author_id = %s 957 if ($post_activation_required) {
958 $query .=
' AND f.pos_status = ' . $this->db->quote(1,
'integer');
961 $res = $this->db->queryF(
963 [
'integer',
'integer',
'integer',
'integer'],
966 $row = $this->db->fetchAssoc(
$res);
967 if (is_array($row)) {
968 return (
int) $row[
'cnt'];
985 u.login, u.lastname, u.firstname, f.pos_author_id, u.usr_id, 986 p.value public_profile, 987 SUM(IF(f.pos_cens = %s, 1, 0)) num_postings 989 INNER JOIN frm_posts_tree t ON f.pos_pk = t.pos_fk 990 INNER JOIN frm_threads th ON t.thr_fk = th.thr_pk 991 INNER JOIN usr_data u ON u.usr_id = f.pos_author_id 992 INNER JOIN frm_data d ON d.top_pk = f.pos_top_fk 993 LEFT JOIN usr_pref p ON p.usr_id = u.usr_id AND p.keyword = %s 994 WHERE t.parent_pos != %s 997 $data_types[] =
'integer';
998 $data_types[] =
'text';
999 $data_types[] =
'integer';
1001 $data[] =
'public_profile';
1004 if ($post_activation_required) {
1005 $query .=
' AND pos_status = %s';
1006 $data_types[] =
'integer';
1011 AND d.top_frm_fk = %s 1012 GROUP BY u.login, p.value,u.lastname, u.firstname, f.pos_author_id 1015 $data_types[] =
'integer';
1018 $res = $this->db->queryF($query, $data_types,
$data);
1019 while ($row = $this->db->fetchAssoc(
$res)) {
1021 !in_array($row[
'public_profile'], [
1026 $row[
'lastname'] =
'';
1027 $row[
'firstname'] =
'';
1030 $row[
'usr_id'] = (
int) $row[
'usr_id'];
1031 $row[
'pos_author_id'] = (
int) $row[
'pos_author_id'];
1032 $row[
'num_postings'] = (
int) $row[
'num_postings'];
1034 $statistic[] = $row;
1042 $res = $this->db->queryF(
1043 'SELECT pos_fk FROM frm_posts_tree WHERE thr_fk = %s AND parent_pos = %s',
1044 [
'integer',
'integer'],
1048 $row = $this->db->fetchObject(
$res);
1050 return (
int) $row->pos_fk;
1071 $rbacreview = $DIC->rbac()->review();
1073 $role_arr = $rbacreview->getRolesOfRoleFolder($a_ref_id);
1074 foreach ($role_arr as $role_id) {
1076 return array_map(
'intval', $rbacreview->assignedUsers($role_id));
1085 if (!isset(self::$moderators_by_ref_id_map[$a_ref_id])) {
1086 self::$moderators_by_ref_id_map[$a_ref_id] = self::_getModerators($a_ref_id);
1089 return in_array($a_usr_id, self::$moderators_by_ref_id_map[$a_ref_id],
true);
1094 $res = $this->db->queryF(
1095 'SELECT * FROM frm_data 1096 INNER JOIN frm_posts ON pos_top_fk = top_pk 1097 INNER JOIN frm_posts_tree tree1 ON tree1.pos_fk = frm_posts.pos_pk AND tree1.parent_pos != 0 1098 WHERE top_frm_fk = %s 1099 AND pos_author_id = %s',
1100 [
'integer',
'integer'],
1104 return $res->numRows();
1109 $res = $this->db->queryF(
1110 'SELECT * FROM frm_data 1111 INNER JOIN frm_posts ON pos_top_fk = top_pk 1112 INNER JOIN frm_posts_tree tree1 ON tree1.pos_fk = frm_posts.pos_pk AND tree1.parent_pos != 0 1113 WHERE top_frm_fk = %s 1114 AND (pos_status = %s OR (pos_status = %s AND pos_author_id = %s)) 1115 AND pos_author_id = %s',
1116 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1120 return $res->numRows();
1128 public function addPostTree(
int $a_tree_id,
int $a_node_id = -1,
string $a_date =
''): bool
1130 $a_date = $a_date ?: date(
'Y-m-d H:i:s');
1132 if ($a_node_id <= 0) {
1133 $a_node_id = $a_tree_id;
1136 $nextId = $this->db->nextId(
'frm_posts_tree');
1138 $this->db->manipulateF(
1140 INSERT INTO frm_posts_tree 1150 VALUES(%s, %s, %s, %s, %s, %s, %s, %s )',
1151 [
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'timestamp'],
1152 [$nextId, $a_tree_id, $a_node_id, 0, 1, 2, 1, $a_date]
1161 public function insertPostNode(
int $a_node_id,
int $a_parent_id,
int $tree_id,
string $a_date =
''): void
1163 $a_date = $a_date ?: date(
'Y-m-d H:i:s');
1166 $res = $this->db->queryF(
1167 'SELECT lft FROM frm_posts_tree WHERE pos_fk = %s AND thr_fk = %s',
1168 [
'integer',
'integer'],
1169 [$a_parent_id, $tree_id]
1171 $row = $this->db->fetchObject(
$res);
1173 $left = (
int) $row->lft;
1179 $this->db->manipulateF(
1181 UPDATE frm_posts_tree 1193 [
'integer',
'integer',
'integer'],
1194 [$left, $left, $tree_id]
1197 $depth = $this->
getPostDepth($a_parent_id, $tree_id) + 1;
1199 $nextId = $this->db->nextId(
'frm_posts_tree');
1200 $this->db->manipulateF(
1202 INSERT INTO frm_posts_tree 1212 VALUES(%s,%s,%s, %s, %s, %s,%s, %s)',
1213 [
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'integer',
'timestamp'],
1229 if ($tree_id !== 0) {
1230 $res = $this->db->queryF(
1231 'SELECT depth FROM frm_posts_tree WHERE pos_fk = %s AND thr_fk = %s',
1232 [
'integer',
'integer'],
1233 [$a_node_id, $tree_id]
1236 $row = $this->db->fetchObject(
$res);
1238 return (
int) $row->depth;
1247 $res = $this->db->queryF(
1248 'SELECT * FROM frm_posts, frm_posts_tree WHERE pos_pk = pos_fk AND parent_pos = %s AND thr_fk = %s',
1249 [
'integer',
'integer'],
1253 if (($row = $this->db->fetchObject(
$res)) !== null) {
1262 $res = $this->db->queryF(
1263 'SELECT * FROM frm_posts, frm_posts_tree WHERE pos_pk = pos_fk AND pos_pk = %s',
1268 if (($row = $this->db->fetchObject(
$res)) !== null) {
1284 $tmp_user =
new ilObjUser((
int) $a_row->pos_display_user_id);
1285 $fullname = $tmp_user->getFullname();
1286 $loginname = $tmp_user->getLogin();
1289 if ($fullname ===
'') {
1290 $fullname = $this->
lng->txt(
'unknown');
1291 if ($a_row->import_name) {
1292 $fullname = $a_row->import_name;
1298 'pos_pk' => (
int) $a_row->pos_pk,
1299 'pos_thr_fk' => (
int) $a_row->pos_thr_fk,
1300 'child' => (
int) $a_row->pos_pk,
1301 'author' => (
int) $a_row->pos_display_user_id,
1302 'alias' => (string) $a_row->pos_usr_alias,
1303 'title' => $fullname,
1304 'loginname' => $loginname,
1305 'message' => (
string) $a_row->pos_message,
1306 'subject' => (string) $a_row->pos_subject,
1307 'pos_cens_com' => (
string) $a_row->pos_cens_com,
1308 'pos_cens' => (
int) $a_row->pos_cens,
1309 'date' => $a_row->fpt_date,
1310 'create_date' => $a_row->pos_date,
1311 'update' => $a_row->pos_update,
1312 'update_user' => (
int) $a_row->update_user,
1313 'tree' => (
int) $a_row->thr_fk,
1314 'parent' => (
int) $a_row->parent_pos,
1315 'lft' => (
int) $a_row->lft,
1316 'rgt' => (
int) $a_row->rgt,
1317 'depth' => (
int) $a_row->depth,
1318 'id' => (
int) $a_row->fpt_pk,
1319 'notify' => (
int) $a_row->notify,
1320 'import_name' => $a_row->import_name,
1321 'pos_status' => (
int) $a_row->pos_status
1330 $res = $this->db->queryF(
1331 'SELECT pos_fk FROM frm_posts_tree WHERE lft BETWEEN %s AND %s AND thr_fk = %s',
1337 while ($post_tree_data = $this->db->fetchAssoc(
$res)) {
1338 $post_ids[] = (
int) $post_tree_data[
'pos_fk'];
1349 $res = $this->db->queryF(
1350 'SELECT lft, rgt FROM frm_posts_tree WHERE thr_fk = %s AND pos_fk = %s AND parent_pos = %s',
1351 [
'integer',
'integer',
'integer'],
1352 [$a_node[
'tree'], $a_node[
'pos_pk'], $a_node[
'parent']]
1355 while ($row = $this->db->fetchObject(
$res)) {
1356 $a_node[
'lft'] = (
int) $row->lft;
1357 $a_node[
'rgt'] = (
int) $row->rgt;
1360 $diff = $a_node[
'rgt'] - $a_node[
'lft'] + 1;
1362 $res = $this->db->queryF(
1363 'SELECT pos_fk FROM frm_posts_tree WHERE lft BETWEEN %s AND %s AND thr_fk = %s',
1364 [
'integer',
'integer',
'integer'],
1365 [$a_node[
'lft'], $a_node[
'rgt'], $a_node[
'tree']]
1368 $deleted_post_ids = [];
1369 while ($treeData = $this->db->fetchAssoc(
$res)) {
1370 $deleted_post_ids[] = (
int) $treeData[
'pos_fk'];
1373 $this->db->manipulateF(
1374 'DELETE FROM frm_posts_tree WHERE lft BETWEEN %s AND %s AND thr_fk = %s',
1375 [
'integer',
'integer',
'integer'],
1376 [$a_node[
'lft'], $a_node[
'rgt'], $a_node[
'tree']]
1379 $this->db->manipulateF(
1381 UPDATE frm_posts_tree 1393 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1394 [$a_node[
'lft'], $diff, $a_node[
'lft'], $diff, $a_node[
'tree']]
1397 return $deleted_post_ids;
1402 $checkTime = time() - (60 * 60);
1403 $session_key =
'frm_visit_' . $this->dbTable .
'_' . $ID;
1407 $query =
'UPDATE ' . $this->dbTable .
' SET visits = visits + 1 WHERE ';
1416 $this->db->manipulateF($query, $data_type, $data_value);
1421 public function prepareText(
string $text,
int $edit = 0,
string $quote_user =
'',
string $type =
''): string
1423 if ($type ===
'export') {
1424 $this->replQuote1 =
"<blockquote class=\"quote\"><hr size=\"1\" color=\"#000000\">";
1425 $this->replQuote2 =
"<hr size=\"1\" color=\"#000000\"/></blockquote>";
1430 if ($quote_user !==
'') {
1431 $lname =
'="' . $quote_user .
'"';
1434 $text =
"[quote$lname]" . $text .
"[/quote]";
1437 $startZ = substr_count($text,
"[quote");
1438 $endZ = substr_count($text,
"[/quote]");
1440 if ($startZ > 0 || $endZ > 0) {
1442 if ($startZ > $endZ) {
1443 $diff = $startZ - $endZ;
1445 for ($i = 0; $i < $diff; $i++) {
1446 if ($type ===
'export') {
1449 $text .=
"[/quote]";
1452 } elseif ($startZ < $endZ) {
1453 $diff = $endZ - $startZ;
1455 for ($i = 0; $i < $diff; $i++) {
1456 if ($type ===
'export') {
1457 $text = $this->txtQuote1 . $text;
1459 $text =
"[quote]" . $text;
1465 $text = preg_replace(
1466 '@\[(quote\s*?=\s*?"([^"]*?)"\s*?)\]@i',
1467 $this->replQuote1 .
'<div class="ilForumQuoteHead">' . $this->
lng->txt(
'quote') .
' ($2)</div>',
1471 $text = str_replace(
1472 [
"[quote]",
"[/quote]"],
1474 $this->replQuote1 .
'<div class="ilForumQuoteHead">' . $this->
lng->txt(
'quote') .
'</div>',
1483 if ($type !==
'export') {
1492 $text = str_replace([
"{",
"}"], [
"{",
"}"], $text);
1503 foreach ($a_ids as $pos_id) {
1505 $files = $forumFiles->getFilesOfPost();
1506 foreach ($files as $file) {
1507 $forumFiles->unlinkFile($file[
'name']);
1519 $this->import_name = $a_import_name;
1526 $res = $this->db->queryF(
1528 SELECT frm_notification.thread_id FROM frm_data, frm_notification, frm_threads 1529 WHERE frm_notification.user_id = %s 1530 AND frm_notification.thread_id = frm_threads.thr_pk 1531 AND frm_threads.thr_top_fk = frm_data.top_pk 1532 AND frm_data.top_frm_fk = %s 1533 GROUP BY frm_notification.thread_id',
1534 [
'integer',
'integer'],
1535 [$user_id, $this->
id]
1538 if (
$res->numRows() > 0) {
1540 $thread_data_types = [];
1542 $query =
' DELETE FROM frm_notification WHERE user_id = %s AND thread_id IN (';
1543 $thread_data[] = $user_id;
1544 $thread_data_types[] =
'integer';
1547 while ($row = $this->db->fetchAssoc(
$res)) {
1548 if ($counter < $res->numRows()) {
1550 $thread_data[] = $row[
'thread_id'];
1551 $thread_data_types[] =
'integer';
1554 if ($counter ===
$res->numRows()) {
1556 $thread_data[] = $row[
'thread_id'];
1557 $thread_data_types[] =
'integer';
1562 $this->db->manipulateF($query, $thread_data_types, $thread_data);
1566 $nextId = $this->db->nextId(
'frm_notification');
1567 $this->db->manipulateF(
1568 'INSERT INTO frm_notification (notification_id, user_id, frm_id) VALUES(%s, %s, %s)',
1569 [
'integer',
'integer',
'integer'],
1570 [$nextId, $user_id, $this->
id]
1579 $this->db->manipulateF(
1580 'DELETE FROM frm_notification WHERE user_id = %s AND frm_id = %s',
1581 [
'integer',
'integer'],
1582 [$user_id, $this->
id]
1590 $res = $this->db->queryF(
1591 'SELECT COUNT(*) cnt FROM frm_notification WHERE user_id = %s AND frm_id = %s',
1592 [
'integer',
'integer'],
1593 [$user_id, $this->
id]
1596 if ($row = $this->db->fetchAssoc(
$res)) {
1597 return (
int) $row[
'cnt'] > 0;
1605 $res = $this->db->queryF(
1606 'SELECT COUNT(*) cnt FROM frm_notification WHERE user_id = %s AND thread_id = %s',
1607 [
'integer',
'integer'],
1608 [$user_id, $thread_id]
1611 if ($row = $this->db->fetchAssoc(
$res)) {
1612 return (
int) $row[
'cnt'] > 0;
1625 $sort = match ($a_sort_mode) {
1626 self::SORT_DATE =>
'thr_date',
1627 default =>
'thr_subject',
1630 $res = $DIC->database()->queryF(
1631 'SELECT thr_pk, thr_subject FROM frm_threads INNER JOIN frm_data ON top_pk = thr_top_fk WHERE top_frm_fk = %s ORDER BY %s',
1632 [
'integer',
'text'],
1637 while ($row = $DIC->database()->fetchObject(
$res)) {
1638 $threads[(
int) $row->thr_pk] = $row->thr_subject;
1648 $res = $DIC->database()->queryF(
'SELECT top_frm_fk FROM frm_data WHERE top_pk = %s', [
'integer'], [$a_for_id]);
1649 if ($row = $DIC->database()->fetchAssoc(
$res)) {
1650 return (
int) $row[
'top_frm_fk'];
1662 if ($sourceThread->getForumId() !== $targetThread->getForumId()) {
1663 throw new ilException(
'not_allowed_to_merge_into_another_forum');
1667 if ($sourceThread->getCreateDate() > $targetThread->getCreateDate()) {
1668 $sourceThreadForMerge = $sourceThread;
1669 $targetThreadForMerge = $targetThread;
1671 $sourceThreadForMerge = $targetThread;
1672 $targetThreadForMerge = $sourceThread;
1675 $threadSubject = $targetThreadForMerge->getSubject();
1677 $targetWasClosedBeforeMerge = $targetThreadForMerge->isClosed();
1678 $sourceThreadForMerge->close();
1680 if (!$targetWasClosedBeforeMerge) {
1681 $targetThreadForMerge->close();
1684 $allSourcePostings = $sourceThreadForMerge->getAllPostIds();
1685 $sourceThreadRootNode = $sourceThreadForMerge->getPostRootNode();
1686 $targetThreadRootNode = $targetThreadForMerge->getPostRootNode();
1688 $sourceThreadRootArray = $this->
getPostNode($sourceThreadRootNode->getId());
1690 $ilAtomQuery = $this->db->buildAtomQuery();
1691 $ilAtomQuery->addTableLock(
'frm_posts');
1692 $ilAtomQuery->addTableLock(
'frm_posts_tree');
1693 $ilAtomQuery->addTableLock(
'frm_threads');
1694 $ilAtomQuery->addTableLock(
'frm_data');
1697 $targetThreadForMerge,
1698 $sourceThreadForMerge,
1699 $targetThreadRootNode,
1700 $sourceThreadRootNode,
1703 $targetRootNodeRgt = $targetThreadRootNode->getRgt();
1704 $targetRootNodeId = $targetThreadRootNode->getId();
1708 $targetThreadRootNode->getId(),
1709 ($targetThreadRootNode->getRgt() + $sourceThreadRootNode->getRgt() - 2)
1713 foreach ($allSourcePostings as $pos_pk) {
1716 if ($post_obj->getId() === $sourceThreadRootNode->getId()) {
1722 $tree->setPosFk($pos_pk);
1724 if ($post_obj->getParentId() === $sourceThreadRootNode->getId()) {
1725 $tree->setParentPos($targetRootNodeId);
1727 $tree->setParentPos($post_obj->getParentId());
1730 $tree->setLft(($post_obj->getLft() + $targetRootNodeRgt) - 2);
1731 $tree->setRgt(($post_obj->getRgt() + $targetRootNodeRgt) - 2);
1733 $tree->setDepth($post_obj->getDepth());
1734 $tree->setTargetThreadId($targetThreadForMerge->getId());
1735 $tree->setSourceThreadId($sourceThreadForMerge->getId());
1741 $sourceThreadForMerge->getId(),
1742 $targetThreadForMerge->getId(),
1743 [$sourceThreadRootNode->getId()]
1746 $ilAtomQuery->run();
1751 $lastPostString = $targetThreadForMerge->getLastPostString();
1752 $exp = explode(
'#', $lastPostString);
1753 if (array_key_exists(2, $exp)) {
1755 $exp[2] = $targetThreadForMerge->getLastPost()->getId();
1756 $lastPostString = implode(
'#', $exp);
1758 $lastPostString = null;
1763 $frm_topic_obj->setNumPosts($sourceThreadForMerge->getNumPosts() + $targetThreadForMerge->getNumPosts());
1764 $frm_topic_obj->setVisits($sourceThreadForMerge->getVisits() + $targetThreadForMerge->getVisits());
1765 $frm_topic_obj->setLastPostString($lastPostString);
1766 $frm_topic_obj->setSubject($threadSubject);
1767 $frm_topic_obj->setId($targetThreadForMerge->getId());
1768 $frm_topic_obj->updateMergedThread();
1770 if (!$targetWasClosedBeforeMerge) {
1771 $targetThreadForMerge->reopen();
1774 $this->
event->raise(
1779 'source_thread_id' => $sourceThreadForMerge->getId(),
1780 'target_thread_id' => $targetThreadForMerge->getId()
1784 $this->
deletePost($sourceThreadRootArray,
false);
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
addPostTree(int $a_tree_id, int $a_node_id=-1, string $a_date='')
getFirstPostNode(int $tree_id)
static get(string $a_var)
isForumNotificationEnabled(int $user_id)
getPostNode(int $post_id)
static mergeForumUserRead(int $merge_source_thread_id, int $merge_target_thread_id)
const PROFILE_ENABLED_LOGGED_IN_USERS
Class Forum core functions for forum.
static array $moderators_by_ref_id_map
getRootPostIdByThread(int $a_thread_id)
setCreateDate(?string $a_createdate)
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
setMDB2WhereCondition(string $query_string, array $data_type, array $data_value)
getUserStatistics(bool $post_activation_required)
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false)
disableForumNotification(int $user_id)
deletePostFiles(array $a_ids)
enableNotification(int $a_user_id)
getPostDepth(int $a_node_id, int $tree_id)
setDbTable(string $dbTable)
static mergePosts(int $sourceThreadId, int $targetThreadId, array $excludedPostIds=[])
moveThreads(array $thread_ids, ilObjForum $src_forum, int $target_obj_id)
setForumRefId(int $a_ref_id)
convertDate(string $date)
static _deleteReadEntries(int $a_post_id)
Class ilForumDraftHistory.
static getInstance(int $a_obj_id=0)
setImportName(?string $a_import_name)
mergeThreads(int $source_id, int $target_id)
insertPostNode(int $a_node_id, int $a_parent_id, int $tree_id, string $a_date='')
insert node under parent node
getNumberOfPublishedUserPostings(int $usr_id, bool $post_activation_required)
fetchPostNodeData(stdClass $a_row)
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
static getInstanceFromArray(array $record)
static updateTargetRootRgt(int $root_node_id, int $rgt)
static _lookupTitle(int $obj_id)
prepareText(string $text, int $edit=0, string $quote_user='', string $type='')
static _lookupObjIdForForumId(int $a_for_id)
const NEWS_NOTICE
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
countUserArticles(int $a_user_id)
static getEmptyInstance()
getSubPathIdsForNode(ilForumPost $post)
getAllThreads(int $a_topic_id, array $params=[], int $limit=0, int $offset=0)
const PROFILE_ENABLED_GLOBAL
enableForumNotification(int $user_id)
generateThread(ilForumTopic $thread, string $message, bool $notify, bool $notify_posts, bool $status=true, bool $withFirstVisibleEntry=true)
setPageHits(int $pageHits)
static _isModerator(int $a_ref_id, int $a_usr_id)
A news item can be created by different sources.
Error Handling & global info handling.
countActiveUserArticles(int $a_user_id)
static getInstance()
Singleton: get instance for use in ILIAS requests with a config loaded from the settings.
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.
deletePost($postIdOrRecord, bool $raiseEvents=true)
postCensorship(ilObjForum $forum, string $message, int $pos_pk, int $cens=0)
static _getModerators(int $a_ref_id)
setImportName(string $a_import_name)
static getSortedThreadSubjects(int $a_obj_id, int $a_sort_mode=self::SORT_DATE)
setForumId(int $a_obj_id)
deletePostTree(array $a_node)
static mergeThreadNotifications($merge_source_thread_id, $merge_target_thread_id)
static set(string $a_var, $a_val)
Set a value.
isThreadNotificationEnabled(int $user_id, int $thread_id)