ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilNewsItem.php
Go to the documentation of this file.
1 <?php
2 
19 const NEWS_NOTICE = 0;
20 const NEWS_MESSAGE = 1;
21 const NEWS_WARNING = 2;
22 
23 const NEWS_TEXT = "text";
24 const NEWS_HTML = "html";
25 const NEWS_AUDIO = "audio";
26 const NEWS_USERS = "users";
27 const NEWS_PUBLIC = "public";
28 
41 {
42  private int $mob_cnt_download = 0;
43  protected int $mob_cnt_play = 0;
44  protected ilDBInterface $db;
45  protected ilTree $tree;
48  protected ilObjUser $user;
49  protected ilLanguage $lng;
50  protected ilCtrl $ctrl;
51  protected int $id = 0;
52  protected string $title = "";
53  protected string $content = "";
54  protected bool $content_html = false;
55  protected int $context_obj_id = 0;
56  protected string $context_obj_type = "";
57  protected int $context_sub_obj_id = 0;
58  protected ?string $context_sub_obj_type = null;
59  protected string $content_type = "text";
60  protected string $creation_date = "";
61  protected string $update_date = "";
62  protected int $user_id = 0;
63  protected int $update_user_id = 0;
64  protected string $visibility = "users";
65  protected string $content_long = "";
66  protected int $priority = 1;
67  protected bool $content_is_lang_var = false;
68  protected int $mob_id = 0;
69  protected string $playtime = "";
70  private static int $privFeedId = 0;
71  private bool $limitation = false;
72  protected bool $content_text_is_lang_var = false;
74  protected ilLogger $log;
75 
76  public function __construct(int $a_id = 0)
77  {
78  global $DIC;
79  $this->main_tpl = $DIC->ui()->mainTemplate();
80 
81  $this->db = $DIC->database();
82  $this->tree = $DIC->repositoryTree();
83  $this->access = $DIC->access();
84  $this->obj_data_cache = $DIC["ilObjDataCache"];
85  $this->user = $DIC->user();
86  $this->lng = $DIC->language();
87  $this->ctrl = $DIC->ctrl();
88  if ($a_id > 0) {
89  $this->setId($a_id);
90  $this->read();
91  }
92  $this->limitation = true;
93  $this->log = $DIC->logger()->news();
94  }
95 
96  public function setId(int $a_id): void
97  {
98  $this->id = $a_id;
99  }
100 
101  public function getId(): int
102  {
103  return $this->id;
104  }
105 
106  public function setTitle(string $a_title): void
107  {
108  $this->title = $a_title;
109  }
110 
111  public function getTitle(): string
112  {
113  return $this->title;
114  }
115 
116  public function setContent(string $a_content): void
117  {
118  $this->content = $a_content;
119  }
120 
121  public function getContent(): string
122  {
123  return $this->content;
124  }
125 
126  public function setContextObjId(int $a_context_obj_id): void
127  {
128  $this->context_obj_id = $a_context_obj_id;
129  }
130 
131  public function getContextObjId(): int
132  {
133  return $this->context_obj_id;
134  }
135 
136  public function setContextObjType(string $a_context_obj_type): void
137  {
138  $this->context_obj_type = $a_context_obj_type;
139  }
140 
141  public function getContextObjType(): string
142  {
144  }
145 
146  public function setContextSubObjId(int $a_context_sub_obj_id): void
147  {
148  $this->context_sub_obj_id = $a_context_sub_obj_id;
149  }
150 
151  public function getContextSubObjId(): int
152  {
154  }
155 
156  public function setContextSubObjType(?string $a_context_sub_obj_type): void
157  {
158  $this->context_sub_obj_type = $a_context_sub_obj_type;
159  }
160 
161  public function getContextSubObjType(): ?string
162  {
164  }
165 
166  public function setContentType(string $a_content_type = "text"): void
167  {
168  $this->content_type = $a_content_type;
169  }
170 
171  public function getContentType(): string
172  {
173  return $this->content_type;
174  }
175 
176  public function setCreationDate(string $a_creation_date): void
177  {
178  $this->creation_date = $a_creation_date;
179  }
180 
181  public function getCreationDate(): string
182  {
183  return $this->creation_date;
184  }
185 
186  public function setUpdateDate(string $a_update_date): void
187  {
188  $this->update_date = $a_update_date;
189  }
190 
191  public function getUpdateDate(): string
192  {
193  return $this->update_date;
194  }
195 
196  public function setUserId(int $a_user_id): void
197  {
198  $this->user_id = $a_user_id;
199  }
200 
201  public function getUserId(): int
202  {
203  return $this->user_id;
204  }
205 
206  public function setUpdateUserId(int $a_val): void
207  {
208  $this->update_user_id = $a_val;
209  }
210 
211  public function getUpdateUserId(): int
212  {
213  return $this->update_user_id;
214  }
215 
219  public function setVisibility(
220  string $a_visibility = "users"
221  ): void {
222  $this->visibility = $a_visibility;
223  }
224 
225  public function getVisibility(): string
226  {
227  return $this->visibility;
228  }
229 
233  public function setContentLong(string $a_content_long): void
234  {
235  $this->content_long = $a_content_long;
236  }
237 
238  public function getContentLong(): string
239  {
240  return $this->content_long;
241  }
242 
243  public function setPriority(int $a_priority = 1): void
244  {
245  $this->priority = $a_priority;
246  }
247 
248  public function getPriority(): int
249  {
250  return $this->priority;
251  }
252 
253  public function setContentIsLangVar(
254  bool $a_content_is_lang_var = false
255  ): void {
256  $this->content_is_lang_var = $a_content_is_lang_var;
257  }
258 
259  public function getContentIsLangVar(): bool
260  {
262  }
263 
264  public function setMobId(int $a_mob_id): void
265  {
266  $this->mob_id = $a_mob_id;
267  }
268 
269  public function getMobId(): int
270  {
271  return $this->mob_id;
272  }
273 
277  public function setPlaytime(string $a_playtime): void
278  {
279  $this->playtime = $a_playtime;
280  }
281 
282  public function getPlaytime(): string
283  {
284  return $this->playtime;
285  }
286 
290  public function setLimitation(bool $a_limitation): void
291  {
292  $this->limitation = $a_limitation;
293  }
294 
295  public function getLimitation(): bool
296  {
297  return $this->limitation;
298  }
299 
300  public function setContentTextIsLangVar(bool $a_val = false): void
301  {
302  $this->content_text_is_lang_var = $a_val;
303  }
304 
305  public function getContentTextIsLangVar(): bool
306  {
308  }
309 
310  public function setMobPlayCounter(int $a_val): void
311  {
312  $this->mob_cnt_play = $a_val;
313  }
314 
315  public function getMobPlayCounter(): int
316  {
317  return $this->mob_cnt_play;
318  }
319 
320  public function setMobDownloadCounter(int $a_val): void
321  {
322  $this->mob_cnt_download = $a_val;
323  }
324 
325  public function getMobDownloadCounter(): int
326  {
328  }
329 
330  public function setContentHtml(bool $a_val): void
331  {
332  $this->content_html = $a_val;
333  }
334 
335  public function getContentHtml(): bool
336  {
337  return $this->content_html;
338  }
339 
344  public function read(): void
345  {
346  $ilDB = $this->db;
347 
348  $query = "SELECT * FROM il_news_item WHERE id = " .
349  $ilDB->quote($this->getId(), "integer");
350  $set = $ilDB->query($query);
351  if ($rec = $ilDB->fetchAssoc($set)) {
352  $this->setTitle((string) $rec["title"]);
353  $this->setContent((string) $rec["content"]);
354  $this->setContextObjId((int) $rec["context_obj_id"]);
355  $this->setContextObjType($rec["context_obj_type"]);
356  $this->setContextSubObjId((int) $rec["context_sub_obj_id"]);
357  $this->setContextSubObjType((string) $rec["context_sub_obj_type"]);
358  $this->setContentType((string) $rec["content_type"]);
359  $this->setCreationDate((string) $rec["creation_date"]);
360  $this->setUpdateDate((string) $rec["update_date"]);
361  $this->setUserId((int) $rec["user_id"]);
362  $this->setUpdateUserId((int) $rec["update_user_id"]);
363  $this->setVisibility((string) $rec["visibility"]);
364  $this->setContentLong((string) $rec["content_long"]);
365  $this->setPriority((int) $rec["priority"]);
366  $this->setContentIsLangVar((bool) $rec["content_is_lang_var"]);
367  $this->setContentTextIsLangVar((bool) $rec["content_text_is_lang_var"]);
368  $this->setMobId((int) $rec["mob_id"]);
369  $this->setPlaytime((string) $rec["playtime"]);
370  $this->setMobPlayCounter((int) $rec["mob_cnt_play"]);
371  $this->setMobDownloadCounter((int) $rec["mob_cnt_download"]);
372  $this->setContentHtml((bool) $rec["content_html"]);
373  }
374  }
375 
380  public function create(): void
381  {
382  $ilDB = $this->db;
383 
384  // insert new record into db
385  $this->setId($ilDB->nextId("il_news_item"));
386  $ilDB->insert("il_news_item", [
387  "id" => ["integer", $this->getId()],
388  "title" => ["text", $this->getTitle()],
389  "content" => ["clob", $this->getContent()],
390  "content_html" => ["integer", (int) $this->getContentHtml()],
391  "context_obj_id" => ["integer", $this->getContextObjId()],
392  "context_obj_type" => ["text", $this->getContextObjType()],
393  "context_sub_obj_id" => ["integer", $this->getContextSubObjId()],
394  "context_sub_obj_type" => ["text", $this->getContextSubObjType()],
395  "content_type" => ["text", $this->getContentType()],
396  "creation_date" => ["timestamp", ilUtil::now()],
397  "update_date" => ["timestamp", ilUtil::now()],
398  "user_id" => ["integer", $this->getUserId()],
399  "update_user_id" => ["integer", $this->getUpdateUserId()],
400  "visibility" => ["text", $this->getVisibility()],
401  "content_long" => ["clob", $this->getContentLong()],
402  "priority" => ["integer", $this->getPriority()],
403  "content_is_lang_var" => ["integer", $this->getContentIsLangVar()],
404  "content_text_is_lang_var" => ["integer", (int) $this->getContentTextIsLangVar()],
405  "mob_id" => ["integer", $this->getMobId()],
406  "playtime" => ["text", $this->getPlaytime()]
407  ]);
408 
409 
410  $news_set = new ilSetting("news");
411  $max_items = $news_set->get("max_items");
412  if ($max_items <= 0) {
413  $max_items = 50;
414  }
415 
416  // limit number of news
417  if ($this->getLimitation()) {
418  // Determine how many rows should be deleted
419  $query = "SELECT count(*) cnt " .
420  "FROM il_news_item " .
421  "WHERE " .
422  "context_obj_id = " . $ilDB->quote($this->getContextObjId(), "integer") .
423  " AND context_obj_type = " . $ilDB->quote($this->getContextObjType(), "text") .
424  " AND context_sub_obj_id = " . $ilDB->quote($this->getContextSubObjId(), "integer") .
425  " AND " . $ilDB->equals("context_sub_obj_type", $this->getContextSubObjType(), "text", true) . " ";
426 
427  $set = $ilDB->query($query);
428  $rec = $ilDB->fetchAssoc($set);
429 
430  // if we have more records than allowed, delete them
431  if (($rec["cnt"] > $max_items) && $this->getContextObjId() > 0) {
432  $query = "SELECT * " .
433  "FROM il_news_item " .
434  "WHERE " .
435  "context_obj_id = " . $ilDB->quote($this->getContextObjId(), "integer") .
436  " AND context_obj_type = " . $ilDB->quote($this->getContextObjType(), "text") .
437  " AND context_sub_obj_id = " . $ilDB->quote($this->getContextSubObjId(), "integer") .
438  " AND " . $ilDB->equals("context_sub_obj_type", $this->getContextSubObjType(), "text", true) .
439  " ORDER BY creation_date ASC";
440 
441  $ilDB->setLimit($rec["cnt"] - $max_items, 0);
442  $del_set = $ilDB->query($query);
443  while ($del_item = $ilDB->fetchAssoc($del_set)) {
444  $del_news = new ilNewsItem((int) $del_item["id"]);
445  $del_news->delete();
446  }
447  }
448  }
449  }
450 
457  public function update(bool $a_as_new = false): void
458  {
459  $ilDB = $this->db;
460 
461  $fields = [
462  "title" => ["text", $this->getTitle()],
463  "content" => ["clob", $this->getContent()],
464  "content_html" => ["integer", (int) $this->getContentHtml()],
465  "context_obj_id" => ["integer", $this->getContextObjId()],
466  "context_obj_type" => ["text", $this->getContextObjType()],
467  "context_sub_obj_id" => ["integer", $this->getContextSubObjId()],
468  "context_sub_obj_type" => ["text", $this->getContextSubObjType()],
469  "content_type" => ["text", $this->getContentType()],
470  "user_id" => ["integer", $this->getUserId()],
471  "update_user_id" => ["integer", $this->getUpdateUserId()],
472  "visibility" => ["text", $this->getVisibility()],
473  "content_long" => ["clob", $this->getContentLong()],
474  "priority" => ["integer", $this->getPriority()],
475  "content_is_lang_var" => ["integer", $this->getContentIsLangVar()],
476  "content_text_is_lang_var" => ["integer", (int) $this->getContentTextIsLangVar()],
477  "mob_id" => ["integer", $this->getMobId()],
478  "mob_cnt_play" => ["integer", $this->getMobPlayCounter()],
479  "mob_cnt_download" => ["integer", $this->getMobDownloadCounter()],
480  "playtime" => ["text", $this->getPlaytime()]
481  ];
482 
483  $now = ilUtil::now();
484  if ($a_as_new) {
485  $fields["creation_date"] = ["timestamp", $now];
486  }
487  $fields["update_date"] = ["timestamp", $now];
488 
489  $ilDB->update("il_news_item", $fields, [
490  "id" => ["integer", $this->getId()]
491  ]);
492  }
493 
494 
499  public static function _getNewsItemsOfUser(
500  int $a_user_id,
501  bool $a_only_public = false,
502  bool $a_prevent_aggregation = false,
503  int $a_per = 0,
504  array &$a_cnt = [],
505  bool $no_auto_generated = false,
506  array $excluded = [],
507  int $a_limit = 0
508  ): array {
509  global $DIC;
510 
511  $ilAccess = $DIC->access();
512  $fav_rep = new ilFavouritesDBRepository();
513 
514  $news_item = new ilNewsItem();
515 
516  $per = $a_per;
517 
518  // this is currently not used
519  $ref_ids = [];
520 
521  if (ilObjUser::_lookupPref($a_user_id, "pd_items_news") !== "n") {
522  // get all items of the personal desktop
523  $pd_items = $fav_rep->getFavouritesOfUser($a_user_id);
524  foreach ($pd_items as $item) {
525  if (!in_array($item["ref_id"], $ref_ids)) {
526  $ref_ids[] = (int) $item["ref_id"];
527  }
528  }
529 
530  // get all memberships
531  $crs_mbs = ilParticipants::_getMembershipByType($a_user_id, ['crs']);
532  $grp_mbs = ilParticipants::_getMembershipByType($a_user_id, ['grp']);
533  $items = array_merge($crs_mbs, $grp_mbs);
534  foreach ($items as $i) {
535  $item_references = ilObject::_getAllReferences($i);
536  if (is_array($item_references) && count($item_references)) {
537  foreach ($item_references as $ref_id) {
538  if (!in_array($ref_id, $ref_ids)) {
539  $ref_ids[] = $ref_id;
540  }
541  }
542  }
543  }
544  }
545 
546  $data = [];
547 
548  foreach ($ref_ids as $ref_id) {
549  if (!$a_only_public) {
550  // this loop should not cost too much performance
551  $acc = $ilAccess->checkAccessOfUser($a_user_id, "read", "", $ref_id);
552 
553  if (!$acc) {
554  continue;
555  }
556  }
557  if (self::getPrivateFeedId() > 0) {
558  global $DIC;
559 
560  $rbacsystem = $DIC->rbac()->system();
561  $acc = $rbacsystem->checkAccessOfUser(self::getPrivateFeedId(), "read", $ref_id);
562 
563  if (!$acc) {
564  continue;
565  }
566  }
567 
568  $obj_id = ilObject::_lookupObjId($ref_id);
569  $obj_type = ilObject::_lookupType($obj_id);
570  $news = $news_item->getNewsForRefId(
571  $ref_id,
572  $a_only_public,
573  false,
574  $per,
575  $a_prevent_aggregation,
576  false,
577  $no_auto_generated,
578  false,
579  $a_user_id,
580  0,
581  $excluded
582  );
583 
584  // counter
585  if (!is_null($a_cnt)) {
586  $a_cnt[$ref_id] = count($news);
587  }
588 
589  $data = self::mergeNews($data, $news);
590  }
591 
592  $data = ilArrayUtil::sortArray($data, "creation_date", "desc", false, true);
593 
594  if ($a_limit > 0) {
595  array_splice($data, $a_limit);
596  }
597  return $data;
598  }
599 
608  public function getNewsForRefId(
609  int $a_ref_id,
610  bool $a_only_public = false,
611  bool $a_stopnesting = false,
612  $a_time_period = 0,
613  bool $a_prevent_aggregation = true,
614  bool $a_forum_group_sequences = false,
615  bool $a_no_auto_generated = false,
616  bool $a_ignore_date_filter = false,
617  int $a_user_id = null,
618  int $a_limit = 0,
619  array $a_excluded = []
620  ): array {
621  $obj_id = ilObject::_lookupObjId($a_ref_id);
622  $obj_type = ilObject::_lookupType($obj_id);
623 
624  // get starting date
625  $starting_date = "";
626  if ($obj_type === "grp" || $obj_type === "crs") {
627  // see #31471, #30687, and ilMembershipNotification
629  $obj_id,
630  'cont_use_news',
631  '1'
632  ) || (
634  $obj_id,
635  'cont_show_news',
636  '1'
638  $obj_id,
639  'news_timeline'
640  )
641  )) {
642  return [];
643  }
644 
645  $hide_news_per_date = ilBlockSetting::_lookup(
646  "news",
647  "hide_news_per_date",
648  0,
649  $obj_id
650  );
651  if ($hide_news_per_date && !$a_ignore_date_filter) {
652  $starting_date = ilBlockSetting::_lookup(
653  "news",
654  "hide_news_date",
655  0,
656  $obj_id
657  );
658  }
659  }
660 
661  if ($obj_type === "cat" && !$a_stopnesting) {
662  $news = $this->getAggregatedChildNewsData(
663  $a_ref_id,
664  $a_only_public,
665  $a_time_period,
666  $a_prevent_aggregation,
667  $starting_date,
668  $a_no_auto_generated,
669  $a_excluded
670  );
671  } elseif (($obj_type === "grp" || $obj_type === "crs") &&
672  !$a_stopnesting) {
673  $news = $this->getAggregatedNewsData(
674  $a_ref_id,
675  $a_only_public,
676  $a_time_period,
677  $a_prevent_aggregation,
678  $starting_date,
679  $a_no_auto_generated,
680  $a_user_id,
681  $a_limit,
682  $a_excluded
683  );
684  } else {
685  $news_item = new ilNewsItem();
686  $news_item->setContextObjId($obj_id);
687  $news_item->setContextObjType($obj_type);
688  $news = $news_item->queryNewsForContext(
689  $a_only_public,
690  $a_time_period,
691  $starting_date,
692  $a_no_auto_generated,
693  false,
694  0,
695  $a_excluded
696  );
697  $unset = [];
698  foreach ($news as $k => $v) {
699  if (!$a_only_public || $v["visibility"] == NEWS_PUBLIC ||
700  ($v["priority"] == 0 &&
702  "news",
703  "public_notifications",
704  0,
705  $obj_id
706  ))) {
707  $news[$k]["ref_id"] = $a_ref_id;
708  } else {
709  $unset[] = $k;
710  }
711  }
712  foreach ($unset as $un) {
713  unset($news[$un]);
714  }
715  }
716 
717  if (!$a_prevent_aggregation) {
718  $news = $this->aggregateForums($news);
719  } elseif ($a_forum_group_sequences) {
720  $news = $this->aggregateForums($news, true);
721  }
722 
723  return $news;
724  }
725 
731  public function getAggregatedNewsData(
732  int $a_ref_id,
733  bool $a_only_public = false,
734  $a_time_period = 0,
735  bool $a_prevent_aggregation = false,
736  string $a_starting_date = "",
737  bool $a_no_auto_generated = false,
738  int $a_user_id = null,
739  int $a_limit = 0,
740  array $a_exclude = []
741  ): array {
742  $tree = $this->tree;
743  $ilAccess = $this->access;
744  $ilObjDataCache = $this->obj_data_cache;
745 
746  // get news of parent object
747  $data = [];
748 
749  // get subtree
750  $cur_node = $tree->getNodeData($a_ref_id);
751 
752  // do not check for lft (materialized path)
753  if ($cur_node) {
754  $nodes = $tree->getSubTree($cur_node, true);
755  } else {
756  $nodes = [];
757  }
758 
759  // preload object data cache
760  $ref_ids = [];
761  $obj_ids = [];
762  $ref_id = [];
763  foreach ($nodes as $node) {
764  $ref_ids[] = (int) $node["child"];
765  $obj_ids[] = (int) $node["obj_id"];
766  }
767 
768  $ilObjDataCache->preloadReferenceCache($ref_ids);
769  if (!$a_only_public) {
771  }
772 
773  // no check, for which of the objects any news are available
774  $news_obj_ids = self::filterObjIdsPerNews($obj_ids, $a_time_period, $a_starting_date);
775  //$news_obj_ids = $obj_ids;
776 
777  // get news for all subtree nodes
778  $contexts = [];
779  foreach ($nodes as $node) {
780  // only go on, if news are available
781  if (!in_array($node["obj_id"], $news_obj_ids)) {
782  continue;
783  }
784 
785  if (!$a_only_public) {
786  if (!$a_user_id) {
787  $acc = $ilAccess->checkAccess("read", "", (int) $node["child"]);
788  } else {
789  $acc = $ilAccess->checkAccessOfUser(
790  $a_user_id,
791  "read",
792  "",
793  (int) $node["child"]
794  );
795  }
796  if (!$acc) {
797  continue;
798  }
799  }
800 
801  $ref_id[$node["obj_id"]] = $node["child"];
802  $contexts[] = [
803  "obj_id" => $node["obj_id"],
804  "obj_type" => $node["type"]
805  ];
806  }
807 
808  // sort and return
809  $news = $this->queryNewsForMultipleContexts(
810  $contexts,
811  $a_only_public,
812  $a_time_period,
813  $a_starting_date,
814  $a_no_auto_generated,
815  $a_user_id,
816  $a_limit,
817  $a_exclude
818  );
819 
820  $to_del = [];
821  foreach ($news as $k => $v) {
822  $news[$k]["ref_id"] = $ref_id[$v["context_obj_id"]];
823  }
824 
825  $data = self::mergeNews($data, $news);
826  $data = ilArrayUtil::sortArray($data, "creation_date", "desc", false, true);
827 
828  if (!$a_prevent_aggregation) {
829  $data = $this->aggregateFiles($data, $a_ref_id);
830  }
831 
832  return $data;
833  }
834 
838  protected function aggregateForums(
839  array $news,
840  bool $a_group_posting_sequence = false
841  ): array {
842  $to_del = [];
843  $forums = [];
844  $last_aggregation_forum = 0;
845 
846  // aggregate
847  foreach ($news as $k => $v) {
848  if ($a_group_posting_sequence && $last_aggregation_forum > 0 &&
849  $last_aggregation_forum != $v["context_obj_id"]) {
850  $forums[$last_aggregation_forum] = null;
851  }
852 
853  if ($v["context_obj_type"] === "frm") {
854  if (!isset($forums[$v["context_obj_id"]])) {
855  // $forums[forum_id] = news_id;
856  $forums[$v["context_obj_id"]] = $k;
857  $last_aggregation_forum = $v["context_obj_id"];
858  } else {
859  $to_del[] = $k;
860  }
861 
862  $news[$k]["no_context_title"] = true;
863 
864  // aggregate every forum into it's "k" news
865  $news[$forums[$news[$k]["context_obj_id"]]]["aggregation"][$k]
866  = $news[$k];
867  $news[$k]["agg_ref_id"]
868  = $news[$k]["ref_id"];
869  $news[$k]["content"] = "";
870  $news[$k]["content_long"] = "";
871  }
872  }
873 
874  // delete double entries
875  foreach ($to_del as $k) {
876  unset($news[$k]);
877  }
878  //var_dump($news[14]["aggregation"]);
879 
880  return $news;
881  }
882 
886  protected function aggregateFiles(
887  array $news,
888  int $a_ref_id
889  ): array {
890  $first_file = "";
891  $to_del = [];
892  foreach ($news as $k => $v) {
893  // aggregate file related news
894  if ($v["context_obj_type"] === "file") {
895  if ($first_file === "") {
896  $first_file = $k;
897  } else {
898  $to_del[] = $k;
899  }
900  $news[$first_file]["aggregation"][$k] = $v;
901  $news[$first_file]["agg_ref_id"] = $a_ref_id;
902  $news[$first_file]["ref_id"] = $a_ref_id;
903  }
904  }
905 
906  foreach ($to_del as $v) {
907  unset($news[$v]);
908  }
909 
910  return $news;
911  }
912 
913 
918  protected function getAggregatedChildNewsData(
919  int $a_ref_id,
920  bool $a_only_public = false,
921  int $a_time_period = 0,
922  bool $a_prevent_aggregation = false,
923  string $a_starting_date = "",
924  bool $a_no_auto_generated = false,
925  array $a_excluded = []
926  ): array {
927  $tree = $this->tree;
928  $ilAccess = $this->access;
929  $ref_id = [];
930  // get news of parent object
931  $data = $this->getNewsForRefId(
932  $a_ref_id,
933  $a_only_public,
934  true,
935  $a_time_period,
936  true,
937  false,
938  $a_no_auto_generated,
939  false,
940  null,
941  0,
942  $a_excluded
943  );
944  foreach ($data as $k => $v) {
945  $data[$k]["ref_id"] = $a_ref_id;
946  }
947 
948  // get childs
949  $nodes = $tree->getChilds($a_ref_id);
950 
951  // no check, for which of the objects any news are available
952  $obj_ids = [];
953  foreach ($nodes as $node) {
954  $obj_ids[] = $node["obj_id"];
955  }
956  $news_obj_ids = self::filterObjIdsPerNews($obj_ids, $a_time_period, $a_starting_date);
957  //$news_obj_ids = $obj_ids;
958 
959  // get news for all subtree nodes
960  $contexts = [];
961  foreach ($nodes as $node) {
962  // only go on, if news are available
963  if (!in_array($node["obj_id"], $news_obj_ids)) {
964  continue;
965  }
966 
967  if (!$a_only_public && !$ilAccess->checkAccess("read", "", (int) $node["child"])) {
968  continue;
969  }
970  $ref_id[$node["obj_id"]] = $node["child"];
971  $contexts[] = [
972  "obj_id" => $node["obj_id"],
973  "obj_type" => $node["type"]
974  ];
975  }
976 
977  $news = $this->queryNewsForMultipleContexts(
978  $contexts,
979  $a_only_public,
980  $a_time_period,
981  $a_starting_date,
982  $a_no_auto_generated,
983  null,
984  0,
985  $a_excluded
986  );
987  foreach ($news as $k => $v) {
988  $news[$k]["ref_id"] = $ref_id[$v["context_obj_id"]];
989  }
990  $data = self::mergeNews($data, $news);
991 
992  // sort and return
993  $data = ilArrayUtil::sortArray($data, "creation_date", "desc", false, true);
994 
995  if (!$a_prevent_aggregation) {
996  $data = $this->aggregateFiles($data, $a_ref_id);
997  }
998 
999  return $data;
1000  }
1001 
1005  public function setContext(
1006  int $a_obj_id,
1007  string $a_obj_type,
1008  int $a_sub_obj_id = 0,
1009  string $a_sub_obj_type = ""
1010  ): void {
1011  $this->setContextObjId($a_obj_id);
1012  $this->setContextObjType($a_obj_type);
1013  $this->setContextSubObjId($a_sub_obj_id);
1014  $this->setContextSubObjType($a_sub_obj_type);
1015  }
1016 
1021  protected static function handleTimePeriod($a_time_period): string
1022  {
1023  // time period is number of days
1024  if (is_numeric($a_time_period)) {
1025  if ($a_time_period > 0) {
1026  return date('Y-m-d H:i:s', time() - ($a_time_period * 24 * 60 * 60));
1027  }
1028  }
1029  // time period is datetime
1030  elseif (preg_match("/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/", $a_time_period)) {
1031  return $a_time_period;
1032  }
1033  return "";
1034  }
1035 
1041  public function queryNewsForContext(
1042  bool $a_for_rss_use = false,
1043  $a_time_period = 0,
1044  string $a_starting_date = "",
1045  bool $a_no_auto_generated = false,
1046  bool $a_oldest_first = false,
1047  int $a_limit = 0,
1048  array $a_exclude = []
1049  ): array {
1050  $ilDB = $this->db;
1051  $ilUser = $this->user;
1052 
1053  $and = "";
1054  if ($a_time_period > 0) {
1055  $limit_ts = self::handleTimePeriod($a_time_period);
1056  $and = " AND creation_date >= " . $ilDB->quote($limit_ts, "timestamp") . " ";
1057  }
1058 
1059  if ($a_starting_date !== "") {
1060  $and .= " AND creation_date > " . $ilDB->quote($a_starting_date, "timestamp") . " ";
1061  }
1062 
1063  if ($a_no_auto_generated) {
1064  $and .= " AND priority = 1 AND content_type = " . $ilDB->quote("text", "text") . " ";
1065  }
1066 
1067  // this is changed with 4.1 (news table for lm pages)
1068  if ($this->getContextSubObjId() > 0) {
1069  $and .= " AND context_sub_obj_id = " . $ilDB->quote($this->getContextSubObjId(), "integer") .
1070  " AND context_sub_obj_type = " . $ilDB->quote($this->getContextSubObjType(), "text");
1071  }
1072 
1073  if (count($a_exclude) > 0) {
1074  $and .= " AND " . $ilDB->in("id", $a_exclude, true, "integer") . " ";
1075  }
1076 
1077  $ordering = ($a_oldest_first)
1078  ? " creation_date ASC, id ASC "
1079  : " creation_date DESC, id DESC ";
1080 
1081  if ($a_for_rss_use && self::getPrivateFeedId() === 0) {
1082  $query = "SELECT * " .
1083  "FROM il_news_item " .
1084  " WHERE " .
1085  "context_obj_id = " . $ilDB->quote($this->getContextObjId(), "integer") .
1086  " AND context_obj_type = " . $ilDB->quote($this->getContextObjType(), "text") .
1087  $and .
1088  " ORDER BY " . $ordering;
1089  } elseif (self::getPrivateFeedId() > 0) {
1090  $query = "SELECT il_news_item.* " .
1091  ", il_news_read.user_id user_read " .
1092  "FROM il_news_item LEFT JOIN il_news_read " .
1093  "ON il_news_item.id = il_news_read.news_id AND " .
1094  " il_news_read.user_id = " . $ilDB->quote(self::getPrivateFeedId(), "integer") .
1095  " WHERE " .
1096  "context_obj_id = " . $ilDB->quote($this->getContextObjId(), "integer") .
1097  " AND context_obj_type = " . $ilDB->quote($this->getContextObjType(), "text") .
1098  $and .
1099  " ORDER BY " . $ordering;
1100  } else {
1101  $query = "SELECT il_news_item.* " .
1102  ", il_news_read.user_id as user_read " .
1103  "FROM il_news_item LEFT JOIN il_news_read " .
1104  "ON il_news_item.id = il_news_read.news_id AND " .
1105  " il_news_read.user_id = " . $ilDB->quote($ilUser->getId(), "integer") .
1106  " WHERE " .
1107  "context_obj_id = " . $ilDB->quote($this->getContextObjId(), "integer") .
1108  " AND context_obj_type = " . $ilDB->quote($this->getContextObjType(), "text") .
1109  $and .
1110  " ORDER BY " . $ordering;
1111  }
1112  //echo $query;
1113  $set = $ilDB->query($query);
1114  $result = [];
1115  while ($rec = $ilDB->fetchAssoc($set)) {
1116  if ($a_limit > 0 && count($result) >= $a_limit) {
1117  continue;
1118  }
1119  if (!$a_for_rss_use || (self::getPrivateFeedId() > 0) || ($rec["visibility"] === NEWS_PUBLIC ||
1120  ((int) $rec["priority"] === 0 &&
1122  "news",
1123  "public_notifications",
1124  0,
1125  (int) $rec["context_obj_id"]
1126  )))) {
1127  $result[$rec["id"]] = $rec;
1128  }
1129  }
1130 
1131  // do we get data for rss and may the time limit by an issue?
1132  // do a second query without time limit.
1133  // this is not very performant, but I do not have a better
1134  // idea. The keep_rss_min setting is currently (Jul 2012) only set
1135  // by mediacasts
1136  if ($a_time_period && $a_for_rss_use) {
1137  $keep_rss_min = ilBlockSetting::_lookup(
1138  "news",
1139  "keep_rss_min",
1140  0,
1141  $this->getContextObjId()
1142  );
1143  if ($keep_rss_min > 0) {
1144  return $this->queryNewsForContext(
1145  true,
1146  0,
1147  $a_starting_date,
1148  $a_no_auto_generated,
1149  $a_oldest_first,
1150  (int) $keep_rss_min,
1151  $a_exclude
1152  );
1153  }
1154  }
1155 
1156  return $result;
1157  }
1158 
1164  public static function queryNewsByIds(array $a_news_ids): array
1165  {
1166  global $DIC;
1167  $ilDB = $DIC->database();
1168  $news = [];
1169  $set = $ilDB->query("SELECT * FROM il_news_item " .
1170  " WHERE " . $ilDB->in("id", $a_news_ids, false, "integer"));
1171  while ($rec = $ilDB->fetchAssoc($set)) {
1172  $news[$rec["id"]] = $rec;
1173  }
1174  return $news;
1175  }
1176 
1182  public function checkNewsExistsForObjects(
1183  array $objects,
1184  $a_time_period = 1
1185  ): array {
1186  $ilDB = $this->db;
1187 
1188  $all = [];
1189 
1190  $this->log->debug("time period: " . $a_time_period);
1191  $limit_ts = self::handleTimePeriod($a_time_period);
1192 
1193  // are there any news items for relevant objects and?
1194  $query = $ilDB->query($q = "SELECT id,context_obj_id,context_obj_type" .
1195  " FROM il_news_item" .
1196  " WHERE " . $ilDB->in("context_obj_id", array_keys($objects), false, "integer") .
1197  " AND creation_date >= " . $ilDB->quote($limit_ts, "timestamp"));
1198  $this->log->debug($q);
1199  while ($rec = $ilDB->fetchAssoc($query)) {
1200  if ($objects[$rec["context_obj_id"]]["type"] == $rec["context_obj_type"]) {
1201  $all[] = (int) $rec["id"];
1202  }
1203  }
1204 
1205  return $all;
1206  }
1207 
1213  array $a_contexts,
1214  bool $a_for_rss_use = false,
1215  $a_time_period = 0,
1216  string $a_starting_date = "",
1217  bool $a_no_auto_generated = false,
1218  int $a_user_id = null,
1219  int $a_limit = 0,
1220  array $a_exclude = []
1221  ): array {
1222  $ilDB = $this->db;
1223  $ilUser = $this->user;
1224 
1225  $and = "";
1226  if ($a_time_period > 0) {
1227  $limit_ts = self::handleTimePeriod($a_time_period);
1228  $and = " AND creation_date >= " . $ilDB->quote($limit_ts, "timestamp") . " ";
1229  }
1230 
1231  if ($a_starting_date !== "") {
1232  $and .= " AND creation_date > " . $ilDB->quote($a_starting_date, "timestamp") . " ";
1233  }
1234 
1235  if ($a_no_auto_generated) {
1236  $and .= " AND priority = 1 AND content_type = " . $ilDB->quote("text", "text") . " ";
1237  }
1238 
1239  if ($a_limit > 0) {
1240  $ilDB->setLimit($a_limit, 0);
1241  }
1242 
1243  if (is_array($a_exclude) && count($a_exclude) > 0) {
1244  $and .= " AND " . $ilDB->in("id", $a_exclude, true, "integer") . " ";
1245  }
1246 
1247  $ids = [];
1248  $type = [];
1249 
1250  foreach ($a_contexts as $cont) {
1251  $ids[] = $cont["obj_id"];
1252  $type[$cont["obj_id"]] = $cont["obj_type"];
1253  }
1254 
1255  if ($a_for_rss_use && self::getPrivateFeedId() === 0) {
1256  $query = "SELECT * " .
1257  "FROM il_news_item " .
1258  " WHERE " .
1259  $ilDB->in("context_obj_id", $ids, false, "integer") . " " .
1260  $and .
1261  " ORDER BY creation_date DESC ";
1262  } elseif (self::getPrivateFeedId() > 0) {
1263  $query = "SELECT il_news_item.* " .
1264  ", il_news_read.user_id as user_read " .
1265  "FROM il_news_item LEFT JOIN il_news_read " .
1266  "ON il_news_item.id = il_news_read.news_id AND " .
1267  " il_news_read.user_id = " . $ilDB->quote(self::getPrivateFeedId(), "integer") .
1268  " WHERE " .
1269  $ilDB->in("context_obj_id", $ids, false, "integer") . " " .
1270  $and .
1271  " ORDER BY creation_date DESC ";
1272  } else {
1273  if ($a_user_id) {
1274  $user_id = $a_user_id;
1275  } else {
1276  $user_id = $ilUser->getId();
1277  }
1278  $query = "SELECT il_news_item.* " .
1279  ", il_news_read.user_id as user_read " .
1280  "FROM il_news_item LEFT JOIN il_news_read " .
1281  "ON il_news_item.id = il_news_read.news_id AND " .
1282  " il_news_read.user_id = " . $ilDB->quote($user_id, "integer") .
1283  " WHERE " .
1284  $ilDB->in("context_obj_id", $ids, false, "integer") . " " .
1285  $and .
1286  " ORDER BY creation_date DESC ";
1287  }
1288 
1289  $set = $ilDB->query($query);
1290  $result = [];
1291  while ($rec = $ilDB->fetchAssoc($set)) {
1292  if ($type[$rec["context_obj_id"]] == $rec["context_obj_type"]) {
1293  if (!$a_for_rss_use || self::getPrivateFeedId() > 0 || ($rec["visibility"] === NEWS_PUBLIC ||
1294  ((int) $rec["priority"] === 0 &&
1296  "news",
1297  "public_notifications",
1298  0,
1299  (int) $rec["context_obj_id"]
1300  )))) {
1301  $result[$rec["id"]] = $rec;
1302  }
1303  }
1304  }
1305 
1306  return $result;
1307  }
1308 
1309 
1314  public static function _setRead(
1315  int $a_user_id,
1316  int $a_news_id
1317  ): void {
1318  global $DIC;
1319 
1320  $ilDB = $DIC->database();
1321  $ilAppEventHandler = $DIC["ilAppEventHandler"];
1322 
1323  $ilDB->replace(
1324  "il_news_read",
1325  [
1326  "user_id" => ["integer", $a_user_id],
1327  "news_id" => ["integer", $a_news_id]
1328  ],
1329  []
1330  );
1331 
1332  $ilAppEventHandler->raise(
1333  "Services/News",
1334  "readNews",
1335  ["user_id" => $a_user_id, "news_ids" => [$a_news_id]]
1336  );
1337  }
1338 
1343  public static function _setUnread(
1344  int $a_user_id,
1345  int $a_news_id
1346  ): void {
1347  global $DIC;
1348 
1349  $ilDB = $DIC->database();
1350  $ilAppEventHandler = $DIC["ilAppEventHandler"];
1351 
1352  $ilDB->manipulate("DELETE FROM il_news_read (user_id, news_id) VALUES (" .
1353  " WHERE user_id = " . $ilDB->quote($a_user_id, "integer") .
1354  " AND news_id = " . $ilDB->quote($a_news_id, "integer"));
1355 
1356  $ilAppEventHandler->raise(
1357  "Services/News",
1358  "unreadNews",
1359  ["user_id" => $a_user_id, "news_ids" => [$a_news_id]]
1360  );
1361  }
1362 
1367  public static function mergeNews(
1368  array $n1,
1369  array $n2
1370  ): array {
1371  foreach ($n2 as $id => $news) {
1372  $n1[$id] = $news;
1373  }
1374 
1375  return $n1;
1376  }
1377 
1382  public static function _getDefaultVisibilityForRefId(int $a_ref_id): string
1383  {
1384  global $DIC;
1385 
1386  $tree = $DIC->repositoryTree();
1387 
1388  $news_set = new ilSetting("news");
1389  $default_visibility = ($news_set->get("default_visibility") != "")
1390  ? $news_set->get("default_visibility")
1391  : "users";
1392 
1393  if ($tree->isInTree($a_ref_id)) {
1394  $path = $tree->getPathFull($a_ref_id);
1395 
1396  foreach ($path as $key => $row) {
1397  if (!in_array($row["type"], ["root", "cat", "crs", "fold", "grp"], true)) {
1398  continue;
1399  }
1400 
1401  $visibility = ilBlockSetting::_lookup(
1402  "news",
1403  "default_visibility",
1404  0,
1405  (int) $row["obj_id"]
1406  );
1407 
1408  if ($visibility != "") {
1409  $default_visibility = $visibility;
1410  }
1411  }
1412  }
1413 
1414  return $default_visibility;
1415  }
1416 
1417 
1422  public function delete(): void
1423  {
1424  $ilDB = $this->db;
1425 
1426  // delete il_news_read entries
1427  $ilDB->manipulate("DELETE FROM il_news_read " .
1428  " WHERE news_id = " . $ilDB->quote($this->getId(), "integer"));
1429 
1430  // delete multimedia object
1431  $mob = $this->getMobId();
1432 
1433  // delete
1434  $query = "DELETE FROM il_news_item" .
1435  " WHERE id = " . $ilDB->quote($this->getId(), "integer");
1436  $ilDB->manipulate($query);
1437 
1438  // delete mob after news, to have a "mob usage" of 0
1439  if ($mob > 0 && ilObject::_exists($mob)) {
1440  $mob = new ilObjMediaObject($mob);
1441  $mob->delete();
1442  }
1443  }
1444 
1450  public static function getNewsOfContext(
1451  int $a_context_obj_id,
1452  string $a_context_obj_type,
1453  int $a_context_sub_obj_id = 0,
1454  string $a_context_sub_obj_type = ""
1455  ): array {
1456  global $DIC;
1457 
1458  $ilDB = $DIC->database();
1459  $and = "";
1460 
1461  if ($a_context_obj_id === 0 || $a_context_obj_type === "") {
1462  return [];
1463  }
1464 
1465  if ($a_context_sub_obj_id > 0) {
1466  $and = " AND context_sub_obj_id = " . $ilDB->quote($a_context_sub_obj_id, "integer") .
1467  " AND context_sub_obj_type = " . $ilDB->quote($a_context_sub_obj_type, "text");
1468  }
1469 
1470  // get news records
1471  $query = "SELECT id FROM il_news_item" .
1472  " WHERE context_obj_id = " . $ilDB->quote($a_context_obj_id, "integer") .
1473  " AND context_obj_type = " . $ilDB->quote($a_context_obj_type, "text") .
1474  $and;
1475 
1476  $news_set = $ilDB->query($query);
1477 
1478  $news_arr = [];
1479  while ($news = $ilDB->fetchAssoc($news_set)) {
1480  $news_arr[] = new ilNewsItem((int) $news["id"]);
1481  }
1482  return $news_arr;
1483  }
1484 
1489  public static function deleteNewsOfContext(
1490  int $a_context_obj_id,
1491  string $a_context_obj_type,
1492  int $a_context_sub_obj_id = 0,
1493  string $a_context_sub_obj_type = ""
1494  ): void {
1495  foreach (self::getNewsOfContext(
1496  $a_context_obj_id,
1497  $a_context_obj_type,
1498  $a_context_sub_obj_id,
1499  $a_context_sub_obj_type
1500  ) as $n) {
1501  $n->delete();
1502  }
1503  }
1504 
1509  public static function _lookupTitle(int $a_news_id): string
1510  {
1511  global $DIC;
1512 
1513  $ilDB = $DIC->database();
1514 
1515  $query = "SELECT title FROM il_news_item WHERE id = " .
1516  $ilDB->quote($a_news_id, "integer");
1517  $set = $ilDB->query($query);
1518  $rec = $ilDB->fetchAssoc($set);
1519  return $rec["title"] ?? '';
1520  }
1521 
1526  public static function _lookupVisibility(int $a_news_id): string
1527  {
1528  global $DIC;
1529 
1530  $ilDB = $DIC->database();
1531 
1532  $query = "SELECT visibility FROM il_news_item WHERE id = " .
1533  $ilDB->quote($a_news_id, "integer");
1534  $set = $ilDB->query($query);
1535  $rec = $ilDB->fetchAssoc($set);
1536 
1537  return $rec["visibility"] ?? NEWS_USERS;
1538  }
1539 
1544  public static function _lookupMobId(int $a_news_id): int
1545  {
1546  global $DIC;
1547 
1548  $ilDB = $DIC->database();
1549 
1550  $query = "SELECT mob_id FROM il_news_item WHERE id = " .
1551  $ilDB->quote($a_news_id, "integer");
1552  $set = $ilDB->query($query);
1553  $rec = $ilDB->fetchAssoc($set);
1554  return (int) ($rec["mob_id"] ?? 0);
1555  }
1556 
1563  public static function filterObjIdsPerNews(
1564  array $a_obj_ids,
1565  $a_time_period = 0,
1566  string $a_starting_date = "",
1567  string $a_ending_date = '',
1568  bool $ignore_period = false
1569  ): array {
1570  global $DIC;
1571 
1572  $ilDB = $DIC->database();
1573 
1574  $and = "";
1575  if ($a_time_period > 0) {
1576  $limit_ts = self::handleTimePeriod($a_time_period);
1577  $and = " AND creation_date >= " . $ilDB->quote($limit_ts, "timestamp") . " ";
1578  }
1579 
1580  if ($a_starting_date !== "") {
1581  $and .= " AND creation_date >= " . $ilDB->quote($a_starting_date, "timestamp");
1582  }
1583 
1584  $query = "SELECT DISTINCT(context_obj_id) AS obj_id FROM il_news_item" .
1585  " WHERE " . $ilDB->in("context_obj_id", $a_obj_ids, false, "integer") . " " . $and;
1586  //" WHERE context_obj_id IN (".implode(ilUtil::quoteArray($a_obj_ids),",").")".$and;
1587 
1588  $set = $ilDB->query($query);
1589  $objs = [];
1590  while ($rec = $ilDB->fetchAssoc($set)) {
1591  $objs[] = $rec["obj_id"];
1592  }
1593 
1594  return $objs;
1595  }
1596 
1600  public static function determineNewsTitleByNewsId(
1601  int $a_news_id,
1602  int $a_agg_ref_id = 0,
1603  array $a_aggregation = []
1604  ): string {
1605  global $DIC;
1606 
1607  $ilDB = $DIC->database();
1608 
1609  $query = "SELECT context_obj_type, content_is_lang_var, title FROM il_news_item WHERE id = " .
1610  $ilDB->quote($a_news_id, "integer");
1611  $set = $ilDB->query($query);
1612  $rec = $ilDB->fetchAssoc($set);
1613 
1614  return self::determineNewsTitle(
1615  $rec["context_obj_type"],
1616  $rec["title"],
1617  $rec["content_is_lang_var"],
1618  $a_agg_ref_id,
1619  $a_aggregation
1620  );
1621  }
1622 
1627  public static function determineNewsTitle(
1628  string $a_context_obj_type,
1629  string $a_title,
1630  bool $a_content_is_lang_var,
1631  int $a_agg_ref_id = 0,
1632  array $a_aggregation = [],
1633  ?ilLanguage $lng = null
1634  ): string {
1635  global $DIC;
1636 
1637  if (is_null($lng)) {
1638  $lng = $DIC->language();
1639  }
1640  $obj_definition = $DIC["objDefinition"];
1641  $tit = "";
1642 
1643  if ($a_agg_ref_id > 0) {
1644  $cnt = count($a_aggregation);
1645 
1646  // forums
1647  if ($a_context_obj_type === "frm") {
1648  if ($cnt > 1) {
1649  return sprintf($lng->txt("news_x_postings"), $cnt);
1650  }
1651 
1652  return $lng->txt("news_1_postings");
1653  }
1654 
1655  // files
1656  $up_cnt = $cr_cnt = 0;
1657  foreach ($a_aggregation as $item) {
1658  if ($item["title"] === "file_updated") {
1659  $up_cnt++;
1660  } else {
1661  $cr_cnt++;
1662  }
1663  }
1664  $sep = "";
1665  if ($cr_cnt === 1) {
1666  $tit = $lng->txt("news_1_file_created");
1667  $sep = "<br />";
1668  } elseif ($cr_cnt > 1) {
1669  $tit = sprintf($lng->txt("news_x_files_created"), $cr_cnt);
1670  $sep = "<br />";
1671  }
1672  if ($up_cnt === 1) {
1673  $tit .= $sep . $lng->txt("news_1_file_updated");
1674  } elseif ($up_cnt > 1) {
1675  $tit .= $sep . sprintf($lng->txt("news_x_files_updated"), $up_cnt);
1676  }
1677  return $tit;
1678  }
1679 
1680  if ($a_content_is_lang_var) {
1681  if ($obj_definition->isPlugin($a_context_obj_type)) {
1682  return ilObjectPlugin::lookupTxtById($a_context_obj_type, $a_title);
1683  }
1684  return $lng->txt($a_title);
1685  }
1686 
1687  return $a_title;
1688  }
1689 
1694  public static function determineNewsContent(
1695  string $a_context_obj_type,
1696  string $a_content,
1697  bool $a_is_lang_var,
1698  ?ilLanguage $lng = null
1699  ): string {
1700  global $DIC;
1701 
1702  if (is_null($lng)) {
1703  $lng = $DIC->language();
1704  }
1705  $obj_definition = $DIC["objDefinition"];
1706 
1707  if ($a_is_lang_var) {
1708  if ($obj_definition->isPlugin($a_context_obj_type)) {
1709  return ilObjectPlugin::lookupTxtById($a_context_obj_type, $a_content);
1710  }
1711  $lng->loadLanguageModule($a_context_obj_type);
1712  return $lng->txt($a_content);
1713  }
1714 
1715  return $a_content;
1716  }
1717 
1722  public static function getFirstNewsIdForContext(
1723  int $a_context_obj_id,
1724  string $a_context_obj_type,
1725  int $a_context_sub_obj_id = 0,
1726  string $a_context_sub_obj_type = ""
1727  ): int {
1728  global $DIC;
1729 
1730  $ilDB = $DIC->database();
1731 
1732  // Determine how many rows should be deleted
1733  $query = "SELECT id " .
1734  "FROM il_news_item " .
1735  "WHERE " .
1736  "context_obj_id = " . $ilDB->quote($a_context_obj_id, "integer") .
1737  " AND context_obj_type = " . $ilDB->quote($a_context_obj_type, "text") .
1738  " AND context_sub_obj_id = " . $ilDB->quote($a_context_sub_obj_id, "integer") .
1739  " AND " . $ilDB->equals("context_sub_obj_type", $a_context_sub_obj_type, "text", true);
1740 
1741  $set = $ilDB->query($query);
1742  $rec = $ilDB->fetchAssoc($set);
1743 
1744  return (int) ($rec["id"] ?? 0);
1745  }
1746 
1751  public static function getLastNewsIdForContext(
1752  int $a_context_obj_id,
1753  string $a_context_obj_type,
1754  int $a_context_sub_obj_id = 0,
1755  string $a_context_sub_obj_type = "",
1756  bool $a_only_today = false
1757  ): int {
1758  global $DIC;
1759 
1760  $ilDB = $DIC->database();
1761 
1762  // Determine how many rows should be deleted
1763  $query = "SELECT id, update_date " .
1764  "FROM il_news_item " .
1765  "WHERE " .
1766  "context_obj_id = " . $ilDB->quote($a_context_obj_id, "integer") .
1767  " AND context_obj_type = " . $ilDB->quote($a_context_obj_type, "text") .
1768  " AND context_sub_obj_id = " . $ilDB->quote($a_context_sub_obj_id, "integer") .
1769  " AND " . $ilDB->equals("context_sub_obj_type", $a_context_sub_obj_type, "text", true) .
1770  " ORDER BY update_date DESC";
1771 
1772  $ilDB->setLimit(1, 0);
1773  $set = $ilDB->query($query);
1774  $id = 0;
1775  if ($rec = $ilDB->fetchAssoc($set)) {
1776  $id = (int) $rec["id"];
1777  if ($a_only_today) {
1778  $now = ilUtil::now();
1779  if (strpos($rec["update_date"], substr($now, 0, 10)) !== 0) {
1780  $id = 0;
1781  }
1782  }
1783  }
1784 
1785  return $id;
1786  }
1787 
1788 
1793  public static function _lookupMediaObjectUsages(int $a_mob_id): array
1794  {
1795  global $DIC;
1796 
1797  $ilDB = $DIC->database();
1798 
1799  $query = "SELECT id " .
1800  "FROM il_news_item " .
1801  "WHERE " .
1802  " mob_id = " . $ilDB->quote($a_mob_id, "integer");
1803 
1804  $usages = [];
1805  $set = $ilDB->query($query);
1806  while ($rec = $ilDB->fetchAssoc($set)) {
1807  $usages[$rec["id"]] = ["type" => "news", "id" => $rec["id"]];
1808  }
1809 
1810  return $usages;
1811  }
1812 
1817  public static function _lookupContextObjId(int $a_news_id): int
1818  {
1819  global $DIC;
1820 
1821  $ilDB = $DIC->database();
1822 
1823  $query = "SELECT context_obj_id " .
1824  "FROM il_news_item " .
1825  "WHERE " .
1826  " id = " . $ilDB->quote($a_news_id, "integer");
1827  $set = $ilDB->query($query);
1828  $rec = $ilDB->fetchAssoc($set);
1829 
1830  return $rec["context_obj_id"];
1831  }
1832 
1836  public static function _lookupDefaultPDPeriod(): int
1837  {
1838  $news_set = new ilSetting("news");
1839  $per = $news_set->get("pd_period");
1840  if ((int) $per === 0) {
1841  $per = 30;
1842  }
1843 
1844  return $per;
1845  }
1846 
1850  public static function _lookupUserPDPeriod(int $a_user_id): int
1851  {
1852  $news_set = new ilSetting("news");
1853  $allow_shorter_periods = $news_set->get("allow_shorter_periods");
1854  $allow_longer_periods = $news_set->get("allow_longer_periods");
1855  $default_per = self::_lookupDefaultPDPeriod();
1856 
1857  $per = ilBlockSetting::_lookup(
1858  "pdnews",
1859  "news_pd_period",
1860  $a_user_id,
1861  0
1862  );
1863 
1864  // news period information
1865  if ($per <= 0 ||
1866  (!$allow_shorter_periods && ($per < $default_per)) ||
1867  (!$allow_longer_periods && ($per > $default_per))
1868  ) {
1869  $per = $default_per;
1870  }
1871 
1872  return (int) $per;
1873  }
1874 
1878  public static function _lookupRSSPeriod(): int
1879  {
1880  $news_set = new ilSetting("news");
1881  $rss_period = $news_set->get("rss_period");
1882  if ((int) $rss_period === 0) { // default to two weeks
1883  $rss_period = 14;
1884  }
1885  return $rss_period;
1886  }
1887 
1891  public static function setPrivateFeedId(int $a_userId): void
1892  {
1893  self::$privFeedId = $a_userId;
1894  }
1895 
1899  public static function getPrivateFeedId(): int
1900  {
1901  return self::$privFeedId;
1902  }
1903 
1908  public function deliverMobFile(
1909  string $a_purpose = "Standard",
1910  bool $a_increase_download_cnt = false
1911  ): bool {
1912  $mob = $this->getMobId();
1913  $mob = new ilObjMediaObject($mob);
1914  $mob_dir = ilObjMediaObject::_getDirectory($mob->getId());
1915 
1916  // check purpose
1917  if (!$mob->hasPurposeItem($a_purpose)) {
1918  return false;
1919  }
1920 
1921  $m_item = $mob->getMediaItem($a_purpose);
1922  if ($m_item->getLocationType() !== "Reference") {
1923  $file = $mob_dir . "/" . $m_item->getLocation();
1924  if (file_exists($file) && is_file($file)) {
1925  if ($a_increase_download_cnt) {
1926  $this->increaseDownloadCounter();
1927  }
1928  ilFileDelivery::deliverFileLegacy($file, $m_item->getLocation(), "", false, false, false);
1929  return true;
1930  }
1931 
1932  $this->main_tpl->setOnScreenMessage('failure', "File not found!", true);
1933  return false;
1934  }
1935 
1936  if ($a_increase_download_cnt) {
1937  $this->increaseDownloadCounter();
1938  }
1939 
1940  ilUtil::redirect($m_item->getLocation());
1941  return true;
1942  }
1943 
1948  public function increaseDownloadCounter(): void
1949  {
1950  $ilDB = $this->db;
1951 
1952  $cnt = $this->getMobDownloadCounter();
1953  $cnt++;
1954  $this->setMobDownloadCounter($cnt);
1955  $ilDB->manipulate(
1956  "UPDATE il_news_item SET " .
1957  " mob_cnt_download = " . $ilDB->quote($cnt, "integer") .
1958  " WHERE id = " . $ilDB->quote($this->getId(), "integer")
1959  );
1960  }
1961 
1967  public function increasePlayCounter(): void
1968  {
1969  $ilDB = $this->db;
1970 
1971  $cnt = $this->getMobPlayCounter();
1972  $cnt++;
1973  $this->setMobPlayCounter($cnt);
1974  $ilDB->manipulate(
1975  "UPDATE il_news_item SET " .
1976  " mob_cnt_play = " . $ilDB->quote($cnt, "integer") .
1977  " WHERE id = " . $ilDB->quote($this->getId(), "integer")
1978  );
1979  }
1980 
1985  public static function prepareNewsDataFromCache(array $a_cres): array
1986  {
1987  global $DIC;
1988 
1989  $ilDB = $DIC->database();
1990 
1991  $data = $a_cres;
1992  $news_ids = array_keys($data);
1993  $set = $ilDB->query("SELECT id FROM il_news_item " .
1994  " WHERE " . $ilDB->in("id", $news_ids, false, "integer"));
1995  $existing_ids = [];
1996  while ($rec = $ilDB->fetchAssoc($set)) {
1997  $existing_ids[] = (int) $rec["id"];
1998  }
1999  //var_dump($existing_ids);
2000  $existing_news = [];
2001  foreach ($data as $k => $v) {
2002  if (in_array($k, $existing_ids)) {
2003  $existing_news[$k] = $v;
2004  }
2005  }
2006 
2007  return $existing_news;
2008  }
2009 }
update(bool $a_as_new=false)
Update item in database.
__construct(int $a_id=0)
static getNewsOfContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Get all news of a context.
static determineNewsContent(string $a_context_obj_type, string $a_content, bool $a_is_lang_var, ?ilLanguage $lng=null)
Determine new content.
checkNewsExistsForObjects(array $objects, $a_time_period=1)
const NEWS_HTML
getNodeData(int $a_node_id, ?int $a_tree_pk=null)
get all information of a node.
static _lookupUserPDPeriod(int $a_user_id)
string $content_type
static _getDefaultVisibilityForRefId(int $a_ref_id)
Get default visibility for reference id.
static _lookupRSSPeriod()
static deleteNewsOfContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Delete all news of a context.
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
string $context_sub_obj_type
static getLastNewsIdForContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="", bool $a_only_today=false)
Get last news id of news set related to a certain context.
static determineNewsTitleByNewsId(int $a_news_id, int $a_agg_ref_id=0, array $a_aggregation=[])
Determine title for news item entry.
ilGlobalTemplateInterface $main_tpl
getAggregatedChildNewsData(int $a_ref_id, bool $a_only_public=false, int $a_time_period=0, bool $a_prevent_aggregation=false, string $a_starting_date="", bool $a_no_auto_generated=false, array $a_excluded=[])
Get news aggregation for child objects (e.g.
static handleTimePeriod($a_time_period)
Convert time period for DB-queries.
static _getNewsItemsOfUser(int $a_user_id, bool $a_only_public=false, bool $a_prevent_aggregation=false, int $a_per=0, array &$a_cnt=[], bool $no_auto_generated=false, array $excluded=[], int $a_limit=0)
Get all news items for a user.
setContentLong(string $a_content_long)
static filterObjIdsPerNews(array $a_obj_ids, $a_time_period=0, string $a_starting_date="", string $a_ending_date='', bool $ignore_period=false)
Checks whether news are available for.
const NEWS_TEXT
increaseDownloadCounter()
Increase download counter.
static int $privFeedId
getChilds(int $a_node_id, string $a_order="", string $a_direction="ASC")
get child nodes of given node
setContextSubObjId(int $a_context_sub_obj_id)
setLimitation(bool $a_limitation)
Set Limitation for number of items.
static _getAllReferences(int $id)
get all reference ids for object ID
static mergeNews(array $n1, array $n2)
Merges two sets of news.
getNewsForRefId(int $a_ref_id, bool $a_only_public=false, bool $a_stopnesting=false, $a_time_period=0, bool $a_prevent_aggregation=true, bool $a_forum_group_sequences=false, bool $a_no_auto_generated=false, bool $a_ignore_date_filter=false, int $a_user_id=null, int $a_limit=0, array $a_excluded=[])
Get News For Ref Id.
isInTree(?int $a_node_id)
get all information of a node.
setUpdateUserId(int $a_val)
setPlaytime(string $a_playtime)
static setPrivateFeedId(int $a_userId)
setContentHtml(bool $a_val)
read()
Read item from database.
setContextObjType(string $a_context_obj_type)
setVisibility(string $a_visibility="users")
loadLanguageModule(string $a_module)
Load language module.
static _lookupPref(int $a_usr_id, string $a_keyword)
ilLanguage $lng
setContextSubObjType(?string $a_context_sub_obj_type)
static _lookupTitle(int $a_news_id)
Lookup News Title.
static now()
Return current timestamp in Y-m-d H:i:s format.
bool $content_is_lang_var
setMobDownloadCounter(int $a_val)
getPathFull(int $a_endnode_id, int $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
$path
Definition: ltiservices.php:32
static _lookupContainerSetting(int $a_id, string $a_keyword, string $a_default_value=null)
static queryNewsByIds(array $a_news_ids)
Query news data by news ids.
setMobId(int $a_mob_id)
static _lookupObjId(int $ref_id)
static deliverFileLegacy(string $a_file, ?string $a_filename=null, ?string $a_mime=null, ?bool $isInline=false, ?bool $removeAfterDelivery=false, ?bool $a_exit_after=true)
global $DIC
Definition: feed.php:28
getAggregatedNewsData(int $a_ref_id, bool $a_only_public=false, $a_time_period=0, bool $a_prevent_aggregation=false, string $a_starting_date="", bool $a_no_auto_generated=false, int $a_user_id=null, int $a_limit=0, array $a_exclude=[])
Get news aggregation (e.g.
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
const NEWS_MESSAGE
static _getDirectory(int $a_mob_id)
Get absolute directory.
$ref_id
Definition: ltiauth.php:67
string $creation_date
const NEWS_PUBLIC
static _lookup(string $a_type, string $a_setting, int $a_user=0, int $a_block_id=0)
Lookup setting from database.
queryNewsForContext(bool $a_for_rss_use=false, $a_time_period=0, string $a_starting_date="", bool $a_no_auto_generated=false, bool $a_oldest_first=false, int $a_limit=0, array $a_exclude=[])
Query news for a context.
static _setUnread(int $a_user_id, int $a_news_id)
Set item unread.
setContentType(string $a_content_type="text")
setTitle(string $a_title)
static _lookupVisibility(int $a_news_id)
Lookup News Visibility.
static preloadData(array $ref_ids)
Preload data to internal cache.
const NEWS_NOTICE
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static determineNewsTitle(string $a_context_obj_type, string $a_title, bool $a_content_is_lang_var, int $a_agg_ref_id=0, array $a_aggregation=[], ?ilLanguage $lng=null)
Determine title for news item entry.
deliverMobFile(string $a_purpose="Standard", bool $a_increase_download_cnt=false)
Deliver mob file.
setContent(string $a_content)
string $key
Consumer key/client ID value.
Definition: System.php:193
setContextObjId(int $a_context_obj_id)
setCreationDate(string $a_creation_date)
ilObjUser $user
aggregateFiles(array $news, int $a_ref_id)
static _lookupMobId(int $a_news_id)
Lookup mob id.
static lookupTxtById(string $plugin_id, string $lang_var)
static redirect(string $a_script)
setUserId(int $a_user_id)
A news item can be created by different sources.
string $visibility
static getPrivateFeedId()
bool $content_text_is_lang_var
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.
$q
Definition: shib_logout.php:21
string $update_date
string $context_obj_type
const NEWS_AUDIO
setId(int $a_id)
static prepareNewsDataFromCache(array $a_cres)
Prepare news data from cache.
setMobPlayCounter(int $a_val)
queryNewsForMultipleContexts(array $a_contexts, bool $a_for_rss_use=false, $a_time_period=0, string $a_starting_date="", bool $a_no_auto_generated=false, int $a_user_id=null, int $a_limit=0, array $a_exclude=[])
setContentTextIsLangVar(bool $a_val=false)
static _setRead(int $a_user_id, int $a_news_id)
Set item read.
const NEWS_USERS
ilAccessHandler $access
static _lookupMediaObjectUsages(int $a_mob_id)
Lookup media object usage(s)
getSubTree(array $a_node, bool $a_with_data=true, array $a_type=[])
get all nodes in the subtree under specified node
string $content_long
static _getMembershipByType(int $a_usr_id, array $a_type, bool $a_only_member_role=false)
get membership by type Get course or group membership
static _lookupType(int $id, bool $reference=false)
setContentIsLangVar(bool $a_content_is_lang_var=false)
setPriority(int $a_priority=1)
ilObjectDataCache $obj_data_cache
create()
Create.
const NEWS_WARNING
setContext(int $a_obj_id, string $a_obj_type, int $a_sub_obj_id=0, string $a_sub_obj_type="")
Set context for news.
static _lookupContextObjId(int $a_news_id)
Context Object ID.
setUpdateDate(string $a_update_date)
ilDBInterface $db
static _lookupDefaultPDPeriod()
increasePlayCounter()
Increase play counter.
aggregateForums(array $news, bool $a_group_posting_sequence=false)
static sortArray(array $array, string $a_array_sortby_key, string $a_array_sortorder="asc", bool $a_numeric=false, bool $a_keep_keys=false)