ILIAS  trunk Revision v12.0_alpha-1329-g1094ddb0c33
class.ilForumNotification.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
30{
32 private static array $node_data_cache = [];
34 private static array $forced_events_cache = [];
35
36 private readonly ilDBInterface $db;
37 private readonly ilObjUser $user;
38 private int $notification_id;
39 private ?int $user_id = null;
40 private int $forum_id;
41 private int $thread_id;
42 private bool $admin_force = false;
43 private bool $user_toggle = false;
44 private int $interested_events = 0;
45 private int $user_id_noti;
46
47 public function __construct(private int $ref_id)
48 {
49 global $DIC;
50
51 $this->db = $DIC->database();
52 $this->user = $DIC->user();
53 $this->forum_id = $DIC['ilObjDataCache']->lookupObjId($ref_id);
54 }
55
56 public function setNotificationId(int $a_notification_id): void
57 {
58 $this->notification_id = $a_notification_id;
59 }
60
61 public function getNotificationId(): int
62 {
64 }
65
66 public function setUserId(?int $a_user_id): void
67 {
68 $this->user_id = $a_user_id;
69 }
70
71 public function getUserId(): ?int
72 {
73 return $this->user_id;
74 }
75
76 public function setForumId(int $a_forum_id): void
77 {
78 $this->forum_id = $a_forum_id;
79 }
80
81 public function getForumId(): int
82 {
83 return $this->forum_id;
84 }
85
86 public function setThreadId(int $a_thread_id): void
87 {
88 $this->thread_id = $a_thread_id;
89 }
90
91 public function getThreadId(): int
92 {
93 return $this->thread_id;
94 }
95
96 public function setInterestedEvents(int $interested_events): void
97 {
98 $this->interested_events = $interested_events;
99 }
100
101 public function getInterestedEvents(): int
102 {
104 }
105
106 public function setAdminForce(bool $a_admin_force): void
107 {
108 $this->admin_force = $a_admin_force;
109 }
110
111 public function getAdminForce(): bool
112 {
113 return $this->admin_force;
114 }
115
116 public function setUserToggle(bool $a_user_toggle): void
117 {
118 $this->user_toggle = $a_user_toggle;
119 }
120
121 public function getUserToggle(): bool
122 {
123 return $this->user_toggle;
124 }
125
126 public function setForumRefId(int $a_ref_id): void
127 {
128 $this->ref_id = $a_ref_id;
129 }
130
131 public function getForumRefId(): int
132 {
133 return $this->ref_id;
134 }
135
136 //user_id of who sets the setting to notify members
137 public function setUserIdNoti(int $a_user_id_noti): void
138 {
139 $this->user_id_noti = $a_user_id_noti;
140 }
141
142 //user_id of who sets the setting to notify members
143 public function getUserIdNoti(): int
144 {
145 return $this->user_id_noti;
146 }
147
148 public function isAdminForceNotification(): bool
149 {
150 $res = $this->db->queryF(
151 '
152 SELECT admin_force_noti FROM frm_notification
153 WHERE user_id = %s
154 AND frm_id = %s
155 AND user_id_noti > %s ',
156 ['integer', 'integer', 'integer'],
157 [(int) $this->getUserId(), $this->getForumId(), 0]
158 );
159
160 if ($row = $this->db->fetchAssoc($res)) {
161 return (bool) $row['admin_force_noti'];
162 }
163
164 return false;
165 }
166
167 public function isUserToggleNotification(): bool
168 {
169 $res = $this->db->queryF(
170 '
171 SELECT user_toggle_noti FROM frm_notification
172 WHERE user_id = %s
173 AND frm_id = %s
174 AND user_id_noti > %s',
175 ['integer', 'integer', 'integer'],
176 [(int) $this->getUserId(), $this->getForumId(), 0]
177 );
178
179 if ($row = $this->db->fetchAssoc($res)) {
180 return (bool) $row['user_toggle_noti'];
181 }
182 return false;
183 }
184
185 public function insertAdminForce(): void
186 {
187 $next_id = $this->db->nextId('frm_notification');
188 $this->setNotificationId($next_id);
189
190 $this->db->manipulateF(
191 '
192 INSERT INTO frm_notification
193 (notification_id, user_id, frm_id, admin_force_noti, user_toggle_noti, interested_events, user_id_noti)
194 VALUES(%s, %s, %s, %s, %s, %s, %s)',
195 ['integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer'],
196 [
197 $next_id,
198 (int) $this->getUserId(),
199 $this->getForumId(),
200 $this->getAdminForce(),
201 $this->getUserToggle(),
202 $this->getInterestedEvents(),
203 $this->user->getId()
204 ]
205 );
206 }
207
208 public function deleteAdminForce(): void
209 {
210 $this->db->manipulateF(
211 '
212 DELETE FROM frm_notification
213 WHERE user_id = %s
214 AND frm_id = %s
215 AND admin_force_noti = %s
216 AND user_id_noti > %s',
217 ['integer', 'integer', 'integer', 'integer'],
218 [(int) $this->getUserId(), $this->getForumId(), 1, 0]
219 );
220 }
221
222 public function deleteUserToggle(): void
223 {
224 $this->db->manipulateF(
225 '
226 DELETE FROM frm_notification
227 WHERE user_id = %s
228 AND frm_id = %s
229 AND admin_force_noti = %s
230 AND user_toggle_noti = %s
231 AND user_id_noti > %s',
232 ['integer', 'integer', 'integer', 'integer', 'integer'],
233 [(int) $this->getUserId(), $this->getForumId(), 1, 1, 0]
234 );
235 }
236
237 public function updateUserToggle(): void
238 {
239 $this->db->manipulateF(
240 'UPDATE frm_notification SET user_toggle_noti = %s WHERE user_id = %s AND frm_id = %s AND admin_force_noti = %s',
241 ['integer', 'integer', 'integer', 'integer'],
242 [$this->getUserToggle(), (int) $this->getUserId(), $this->getForumId(), 1]
243 );
244 }
245
246 /* If a new member enters a Course or a Group, this function checks
247 * if this CRS/GRP contains a forum and a notification setting set by admin or moderator
248 * and inserts the new member into frm_notification
249 * */
250 public static function checkForumsExistsInsert(int $ref_id, int $user_id): void
251 {
252 global $DIC;
253
254 $ilUser = $DIC->user();
255
256 $node_data = self::getCachedNodeData($ref_id);
257
258 foreach ($node_data as $data) {
259 //check frm_properties if frm_noti is enabled
260 $frm_noti = new ilForumNotification((int) $data['ref_id']);
261 if ($user_id !== 0) {
262 $frm_noti->setUserId($user_id);
263 } else {
264 $frm_noti->setUserId($ilUser->getId());
265 }
266
267 $properties = ilForumProperties::getInstance((int) $data['obj_id']);
268 if ($properties->getNotificationType() !== NotificationType::DEFAULT) {
269 if ($properties->isAdminForceNoti()) {
270 $frm_noti->setInterestedEvents($properties->getInterestedEvents());
271 }
272
273 $frm_noti->setAdminForce($properties->isAdminForceNoti());
274 $frm_noti->setUserToggle($properties->isUserToggleNoti());
275 $frm_noti->setForumId($properties->getObjId());
276 if (!$frm_noti->existsNotification()) {
277 $frm_noti->insertAdminForce();
278 }
279 }
280 }
281 }
282
283 public static function checkForumsExistsDelete(int $ref_id, int $user_id): void
284 {
285 global $DIC;
286
287 $ilUser = $DIC->user();
288
289 $node_data = self::getCachedNodeData($ref_id);
290
291 foreach ($node_data as $data) {
292 $frm_noti = new ilForumNotification((int) $data['ref_id']);
293 $objFrmMods = new ilForumModerators((int) $data['ref_id']);
294 $moderator_ids = $objFrmMods->getCurrentModerators();
295
296 if ($user_id !== 0) {
297 $frm_noti->setUserId($user_id);
298 } else {
299 $frm_noti->setUserId($ilUser->getId());
300 }
301
302 $frm_noti->setForumId((int) $data['obj_id']);
303 if (!in_array($frm_noti->getUserId(), $moderator_ids, true)) {
304 $frm_noti->deleteAdminForce();
305 }
306 }
307 }
308
309 public static function getCachedNodeData(int $ref_id): array
310 {
311 global $DIC;
312
313 if (!array_key_exists($ref_id, self::$node_data_cache)) {
314 $container_node = $DIC->repositoryTree()->getNodeData($ref_id);
315 if (!isset($container_node['child'])) {
316 return [];
317 }
318
319 $node_data = $DIC->repositoryTree()->getSubTree(
320 $container_node,
321 true,
322 ['frm']
323 );
324 $node_data = array_filter($node_data, static function (array $forum_node) use ($DIC, $ref_id): bool {
325 // filter out forum if a grp lies in the path (#0027702)
326 foreach ($DIC->repositoryTree()->getNodePath((int) $forum_node['child'], $ref_id) as $path_node) {
327 $notRootNode = (int) $path_node['child'] !== $ref_id;
328 $isGroup = $path_node['type'] === 'grp';
329 if ($notRootNode && $isGroup) {
330 return false;
331 }
332 }
333
334 return true;
335 });
336 self::$node_data_cache[$ref_id] = $node_data;
337 }
338
339 return self::$node_data_cache[$ref_id];
340 }
341
342 public static function _clearForcedForumNotifications(array $move_tree_event): void
343 {
344 global $DIC;
345 $ilDB = $DIC->database();
346
347 if ($move_tree_event['tree'] !== 'tree') {
348 return;
349 }
350
352 $source_forum = ilObjectFactory::getInstanceByRefId((int) $move_tree_event['source_id']);
353 if ($source_forum->isParentMembershipEnabledContainer()) {
354 $ilDB->manipulateF(
355 'DELETE FROM frm_notification WHERE frm_id = %s AND admin_force_noti = %s',
356 ['integer', 'integer'],
357 [$source_forum->getId(), 1]
358 );
359 }
360 }
361
362 public function update(): void
363 {
364 $this->db->manipulateF(
365 'UPDATE frm_notification SET admin_force_noti = %s, user_toggle_noti = %s, ' .
366 'interested_events = %s WHERE user_id = %s AND frm_id = %s',
367 ['integer', 'integer', 'integer', 'integer', 'integer'],
368 [
369 (int) $this->getAdminForce(),
370 (int) $this->getUserToggle(),
371 $this->getInterestedEvents(),
372 (int) $this->getUserId(),
373 $this->getForumId()
374 ]
375 );
376 }
377
378 public function deleteNotificationAllUsers(): void
379 {
380 $this->db->manipulateF(
381 'DELETE FROM frm_notification WHERE frm_id = %s AND user_id_noti > %s',
382 ['integer', 'integer'],
383 [$this->getForumId(), 0]
384 );
385 }
386
390 public function read(): array
391 {
392 $res = $this->db->queryF('SELECT * FROM frm_notification WHERE frm_id = %s', ['integer'], [$this->getForumId()]);
393
394 $result = [];
395 while ($row = $this->db->fetchAssoc($res)) {
396 $result[(int) $row['user_id']] = [
397 'notification_id' => (int) $row['notification_id'],
398 'user_id' => (int) $row['user_id'],
399 'frm_id' => (int) $row['frm_id'],
400 'thread_id' => (int) $row['thread_id'],
401 'admin_force_noti' => (int) $row['admin_force_noti'],
402 'user_toggle_noti' => (int) $row['user_toggle_noti'],
403 'interested_events' => (int) $row['interested_events'],
404 'user_id_noti' => (int) $row['user_id_noti']
405 ];
406 }
407
408 return $result;
409 }
410
411 public static function mergeThreadNotifications($merge_source_thread_id, $merge_target_thread_id): void
412 {
413 global $DIC;
414
415 $ilDB = $DIC->database();
416
417 $res = $ilDB->queryF(
418 'SELECT notification_id, user_id FROM frm_notification WHERE frm_id = %s AND thread_id = %s ORDER BY user_id ASC',
419 ['integer', 'integer'],
420 [0, $merge_source_thread_id]
421 );
422
423 $res_2 = $ilDB->queryF(
424 'SELECT DISTINCT user_id FROM frm_notification WHERE frm_id = %s AND thread_id = %s ORDER BY user_id ASC',
425 ['integer', 'integer'],
426 [0, $merge_target_thread_id]
427 );
428
429 $users_already_notified = [];
430 while ($users_row = $ilDB->fetchAssoc($res_2)) {
431 $users_already_notified[(int) $users_row['user_id']] = (int) $users_row['user_id'];
432 }
433
434 while ($row = $ilDB->fetchAssoc($res)) {
435 if (isset($users_already_notified[(int) $row['user_id']])) {
436 $ilDB->manipulateF(
437 'DELETE FROM frm_notification WHERE notification_id = %s',
438 ['integer'],
439 [$row['notification_id']]
440 );
441 } else {
442 $ilDB->update(
443 'frm_notification',
444 ['thread_id' => ['integer', $merge_target_thread_id]],
445 ['thread_id' => ['integer', $merge_source_thread_id]]
446 );
447 }
448 }
449 }
450
451 public function existsNotification(): bool
452 {
453 $res = $this->db->queryF(
454 'SELECT user_id FROM frm_notification WHERE user_id = %s AND frm_id = %s AND admin_force_noti = %s',
455 ['integer', 'integer', 'integer'],
456 [(int) $this->getUserId(), $this->getForumId(), (int) $this->getAdminForce()]
457 );
458
459 return $this->db->numRows($res) > 0;
460 }
461
462 public function cloneFromSource(int $sourceRefId): void
463 {
464 $sourceNotificationSettings = new self($sourceRefId);
465 $records = $sourceNotificationSettings->read();
466
467 foreach ($records as $usrId => $row) {
468 $this->setUserId($usrId);
469 $this->setAdminForce((bool) $row['admin_force_noti']);
470 $this->setUserToggle((bool) $row['user_toggle_noti']);
471 $this->setUserIdNoti((int) $row['user_id_noti']);
472 $this->setInterestedEvents((int) $row['interested_events']);
473
474 $this->insertAdminForce();
475 }
476 }
477
478 public function updateInterestedEvents(): void
479 {
480 $this->db->manipulateF(
481 'UPDATE frm_notification SET interested_events = %s WHERE user_id = %s AND frm_id = %s',
482 ['integer', 'integer', 'integer'],
483 [$this->getInterestedEvents(), (int) $this->getUserId(), $this->getForumId()]
484 );
485 }
486
487 public function readInterestedEvents(): int
488 {
489 $interested_events = ilForumNotificationEvents::DEACTIVATED;
490
491 $this->db->setLimit(1);
492 $res = $this->db->queryF(
493 'SELECT interested_events FROM frm_notification WHERE user_id = %s AND frm_id = %s',
494 ['integer', 'integer'],
495 [(int) $this->getUserId(), $this->getForumId()]
496 );
497
498 while ($row = $this->db->fetchAssoc($res)) {
499 $interested_events = (int) $row['interested_events'];
500 }
501
502 return $interested_events;
503 }
504
508 public function readAllForcedEvents(): array
509 {
510 $res = $this->db->queryF(
511 'SELECT * FROM frm_notification WHERE admin_force_noti = %s AND frm_id = %s',
512 ['integer', 'integer'],
513 [1, $this->forum_id]
514 );
515
516 while ($row = $this->db->fetchAssoc($res)) {
517 $notificationConfig = new self($this->ref_id);
518 $notificationConfig->setNotificationId((int) $row['notification_id']);
519 $notificationConfig->setUserId((int) $row['user_id']);
520 $notificationConfig->setForumId((int) $row['frm_id']);
521 $notificationConfig->setAdminForce((bool) $row['admin_force_noti']);
522 $notificationConfig->setUserToggle((bool) $row['user_toggle_noti']);
523 $notificationConfig->setInterestedEvents((int) $row['interested_events']);
524
525 self::$forced_events_cache[(int) $row['user_id']] = $notificationConfig;
526 }
527
528 return self::$forced_events_cache;
529 }
530
531 public function getForcedEventsObjectByUserId(int $user_id): self
532 {
533 if (!isset(self::$forced_events_cache[$user_id])) {
534 $this->readAllForcedEvents();
535 }
536
537 if (!isset(self::$forced_events_cache[$user_id])) {
538 self::$forced_events_cache[$user_id] = $this->createMissingNotification($user_id);
539 }
540
541 return self::$forced_events_cache[$user_id];
542 }
543
544 private function createMissingNotification(int $user_id): self
545 {
546 $new_object = new self($this->ref_id);
547 $new_object->setUserId($user_id);
548 $new_object->setForumId($this->forum_id);
549 $new_object->insertAdminForce();
550
551 return $new_object;
552 }
553
562 array $all_context_usr_ids,
563 ilForumProperties $effective_properties,
564 ?ilForumProperties $former_properties = null
565 ): void {
566 $existing_notification_records = $this->read();
567 if ($effective_properties->getNotificationType() === NotificationType::DEFAULT) {
568 foreach ($existing_notification_records as $user_id => $row) {
569 $this->setUserId($user_id);
570 $this->setAdminForce($effective_properties->isAdminForceNoti());
571 $this->setUserToggle($effective_properties->isUserToggleNoti());
572 $this->setInterestedEvents((int) $row['interested_events']);
573 $this->update();
574 }
575
576 return;
577 }
578
579 if ($effective_properties->getNotificationType() === NotificationType::ALL_USERS) {
580 foreach ($existing_notification_records as $user_id => $row) {
581 $this->setUserId($user_id);
582 $this->setAdminForce($effective_properties->isAdminForceNoti());
583 $this->setUserToggle($effective_properties->isUserToggleNoti());
584
585 if ($effective_properties->isUserToggleNoti()) {
586 // If the user is not allowed to change subscription settings, we reset the "Events of Interest" to default
587 $this->setInterestedEvents($effective_properties->getInterestedEvents());
588 } else {
589 // We keep existing "Events of Interest" if the user is still allowed to change subcription settings
590 $this->setInterestedEvents((int) $row['interested_events']);
591 }
592
593 $this->update();
594 }
595
596 foreach ($all_context_usr_ids as $user_id) {
597 if (array_key_exists($user_id, $existing_notification_records)) {
598 continue;
599 }
600
601 $this->setUserId($user_id);
602 $this->setAdminForce($effective_properties->isAdminForceNoti());
603 $this->setUserToggle($effective_properties->isUserToggleNoti());
604 $this->setInterestedEvents($effective_properties->getInterestedEvents());
605 $this->insertAdminForce();
606 }
607
608 return;
609 }
610
611 if ($effective_properties->getNotificationType() === NotificationType::PER_USER) {
612 foreach ($existing_notification_records as $user_id => $row) {
613 $this->setUserId($user_id);
614 $this->setAdminForce($effective_properties->isAdminForceNoti());
615 // For existing users, we keep the flag whether the user is albe to change subcription settings
616 $this->setUserToggle((bool) $row['user_toggle_noti']);
617
618 if ((int) $row['user_toggle_noti'] === 1) {
619 // If the user is not allowed to change subscription settings, we reset the "Events of Interest" to default
620 $this->setInterestedEvents($effective_properties->getInterestedEvents());
621 } else {
622 // We keep existing "Events of Interest" if the user is still allowed to change subcription settings
623 $this->setInterestedEvents((int) $row['interested_events']);
624 }
625
626 $this->update();
627 }
628
629 foreach ($all_context_usr_ids as $user_id) {
630 if (array_key_exists($user_id, $existing_notification_records)) {
631 continue;
632 }
633
634 $this->setUserId($user_id);
635 $this->setAdminForce($effective_properties->isAdminForceNoti());
636 $this->setUserToggle($effective_properties->isUserToggleNoti());
637 $this->setInterestedEvents($effective_properties->getInterestedEvents());
638 $this->insertAdminForce();
639 }
640 }
641 }
642}
Class ilForumModerators.
Class ilForumNotification.
applyTypeConfigurationFor(array $all_context_usr_ids, ilForumProperties $effective_properties, ?ilForumProperties $former_properties=null)
Aligns frm_notification rows for this forum with the effective notification mode and properties.
static checkForumsExistsInsert(int $ref_id, int $user_id)
static mergeThreadNotifications($merge_source_thread_id, $merge_target_thread_id)
setUserToggle(bool $a_user_toggle)
setInterestedEvents(int $interested_events)
readonly ilDBInterface $db
getForcedEventsObjectByUserId(int $user_id)
setUserIdNoti(int $a_user_id_noti)
setNotificationId(int $a_notification_id)
static getCachedNodeData(int $ref_id)
setAdminForce(bool $a_admin_force)
__construct(private int $ref_id)
static checkForumsExistsDelete(int $ref_id, int $user_id)
static getInstance(int $a_obj_id=0)
User class.
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
Interface ilDBInterface.
$ref_id
Definition: ltiauth.php:66
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:26