ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
class.ilForumCronNotification.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once "Services/Cron/classes/class.ilCronJob.php";
5include_once "./Modules/Forum/classes/class.ilForumMailNotification.php";
6
14{
16
20 protected $settings;
21
25 protected $logger;
26
30 public static $providerObject = array();
31
35 protected static $deleted_ids_cache = array();
36
40 protected static $ref_ids_by_obj_id = array();
41
45 protected static $accessible_ref_ids_by_user = array();
46
50 protected $num_sent_messages = 0;
51
55 public function __construct()
56 {
57 $this->settings = new ilSetting('frma');
58 }
59
60 public function getId()
61 {
62 return "frm_notification";
63 }
64
65 public function getTitle()
66 {
67 global $lng;
68
69 return $lng->txt("cron_forum_notification");
70 }
71
72 public function getDescription()
73 {
74 global $lng;
75
76 return $lng->txt("cron_forum_notification_crob_desc");
77 }
78
79 public function getDefaultScheduleType()
80 {
82 }
83
84 public function getDefaultScheduleValue()
85 {
86 return 1;
87 }
88
89 public function hasAutoActivation()
90 {
91 return false;
92 }
93
94 public function hasFlexibleSchedule()
95 {
96 return true;
97 }
98
102 public function hasCustomSettings()
103 {
104 return true;
105 }
106
110 public function keepAlive()
111 {
112 $this->logger->debug('Sending ping to cron manager ...');
113 \ilCronManager::ping($this->getId());
114 $this->logger->debug(sprintf('Current memory usage: %s', memory_get_usage(true)));
115 }
116
120 public function run()
121 {
122 global $ilDB, $ilSetting, $lng;
123
124 $this->logger = $GLOBALS['DIC']->logger()->frm();
125
127
128 $lng->loadLanguageModule('forum');
129
130 $this->logger->info('Started forum notification job ...');
131
132 if(!($last_run_datetime = $ilSetting->get('cron_forum_notification_last_date')))
133 {
134 $last_run_datetime = null;
135 }
136
137 $this->num_sent_messages = 0;
138 $cj_start_date = date('Y-m-d H:i:s');
139
140 if($last_run_datetime != null &&
141 checkDate(date('m', strtotime($last_run_datetime)), date('d', strtotime($last_run_datetime)), date('Y', strtotime($last_run_datetime))))
142 {
143 $threshold = max(strtotime($last_run_datetime), strtotime('-' . (int)$this->settings->get('max_notification_age', 30) . ' days', time()));
144 }
145 else
146 {
147 $threshold = strtotime('-' . (int)$this->settings->get('max_notification_age', 30) . ' days', time());
148 }
149
150 $this->logger->info(sprintf('Threshold for forum event determination is: %s', date('Y-m-d H:i:s', $threshold)));
151
152 $threshold_date = date('Y-m-d H:i:s', $threshold);
153 $new_posts_condition = '
154 frm_posts.pos_status = %s AND (
155 (frm_posts.pos_date >= %s AND frm_posts.pos_date = frm_posts.pos_activation_date) OR
156 (frm_posts.pos_activation_date >= %s AND frm_posts.pos_date < frm_posts.pos_activation_date)
157 ) ';
158 $types = array('integer', 'timestamp', 'timestamp');
159 $values = array(1, $threshold_date, $threshold_date);
160
161 /*** new posts ***/
162 $res = $ilDB->queryf('
163 SELECT frm_threads.thr_subject thr_subject,
164 frm_data.top_name top_name,
165 frm_data.top_frm_fk obj_id,
166 frm_notification.user_id user_id,
167 frm_threads.thr_pk thread_id,
168 frm_posts.*
169 FROM frm_notification, frm_posts, frm_threads, frm_data
170 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$new_posts_condition.'
171 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
172 OR (frm_threads.thr_pk = frm_notification.thread_id
173 AND frm_data.top_pk = frm_threads.thr_top_fk) )
174 AND frm_posts.pos_display_user_id != frm_notification.user_id
175 ORDER BY frm_posts.pos_date ASC',
176 $types,
177 $values
178 );
179
180 $numRows = $ilDB->numRows($res);
181 if($numRows > 0)
182 {
183 $this->logger->info(sprintf('Sending notifications for %s "new posting" events ...', $numRows));
184 $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_NEW);
185 $this->logger->info(sprintf('Sent notifications for new postings ...'));
186 }
187
188 $this->keepAlive();
189
190 /*** updated posts ***/
191 $updated_condition = '
192 frm_posts.pos_cens = %s AND frm_posts.pos_status = %s AND
193 (frm_posts.pos_update > frm_posts.pos_date AND frm_posts.pos_update >= %s) ';
194 $types = array('integer', 'integer', 'timestamp');
195 $values = array(0, 1, $threshold_date);
196
197 $res = $ilDB->queryf('
198 SELECT frm_threads.thr_subject thr_subject,
199 frm_data.top_name top_name,
200 frm_data.top_frm_fk obj_id,
201 frm_notification.user_id user_id,
202 frm_threads.thr_pk thread_id,
203 frm_posts.*
204 FROM frm_notification, frm_posts, frm_threads, frm_data
205 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$updated_condition.'
206 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
207 OR (frm_threads.thr_pk = frm_notification.thread_id
208 AND frm_data.top_pk = frm_threads.thr_top_fk) )
209 AND frm_posts.pos_display_user_id != frm_notification.user_id
210 ORDER BY frm_posts.pos_date ASC',
211 $types,
212 $values
213 );
214
215 $numRows = $ilDB->numRows($res);
216 if($numRows > 0)
217 {
218 $this->logger->info(sprintf('Sending notifications for %s "updated posting" events ...', $numRows));
219 $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_UPDATED);
220 $this->logger->info(sprintf('Sent notifications for updated postings ...'));
221 }
222
223 $this->keepAlive();
224
225 /*** censored posts ***/
226 $censored_condition = '
227 frm_posts.pos_cens = %s AND frm_posts.pos_status = %s AND
228 (frm_posts.pos_cens_date >= %s AND frm_posts.pos_cens_date > frm_posts.pos_activation_date ) ';
229 $types = array('integer', 'integer', 'timestamp');
230 $values = array(1, 1, $threshold_date);
231
232 $res = $ilDB->queryf('
233 SELECT frm_threads.thr_subject thr_subject,
234 frm_data.top_name top_name,
235 frm_data.top_frm_fk obj_id,
236 frm_notification.user_id user_id,
237 frm_threads.thr_pk thread_id,
238 frm_posts.*
239 FROM frm_notification, frm_posts, frm_threads, frm_data
240 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$censored_condition.'
241 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
242 OR (frm_threads.thr_pk = frm_notification.thread_id
243 AND frm_data.top_pk = frm_threads.thr_top_fk) )
244 AND (frm_posts.pos_display_user_id != frm_notification.user_id)
245 ORDER BY frm_posts.pos_date ASC',
246 $types,
247 $values
248 );
249
250 $numRows = $ilDB->numRows($res);
251 if($numRows > 0)
252 {
253 $this->logger->info(sprintf('Sending notifications for %s "censored posting" events ...', $numRows));
254 $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_CENSORED);
255 $this->logger->info(sprintf('Sent notifications for new censored ...'));
256 }
257
258 $this->keepAlive();
259
260 /*** uncensored posts ***/
261 $uncensored_condition = '
262 frm_posts.pos_cens = %s AND frm_posts.pos_status = %s AND
263 (frm_posts.pos_cens_date >= %s AND frm_posts.pos_cens_date > frm_posts.pos_activation_date ) ';
264 $types = array('integer', 'integer', 'timestamp');
265 $values = array(0, 1, $threshold_date);
266
267 $res = $ilDB->queryf('
268 SELECT frm_threads.thr_subject thr_subject,
269 frm_data.top_name top_name,
270 frm_data.top_frm_fk obj_id,
271 frm_notification.user_id user_id,
272 frm_threads.thr_pk thread_id,
273 frm_posts.*
274 FROM frm_notification, frm_posts, frm_threads, frm_data
275 WHERE frm_posts.pos_thr_fk = frm_threads.thr_pk AND '.$uncensored_condition.'
276 AND ((frm_threads.thr_top_fk = frm_data.top_pk AND frm_data.top_frm_fk = frm_notification.frm_id)
277 OR (frm_threads.thr_pk = frm_notification.thread_id
278 AND frm_data.top_pk = frm_threads.thr_top_fk) )
279 AND frm_posts.pos_display_user_id != frm_notification.user_id
280 ORDER BY frm_posts.pos_date ASC',
281 $types,
282 $values
283 );
284
285 $numRows = $ilDB->numRows($res);
286 if($numRows > 0)
287 {
288 $this->logger->info(sprintf('Sending notifications for %s "uncensored posting" events ...', $numRows));
289 $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_UNCENSORED);
290 $this->logger->info(sprintf('Sent notifications for uncensored postings ...'));
291 }
292
293 $this->keepAlive();
294
295 /*** deleted threads ***/
296 $res = $ilDB->queryF('
297 SELECT frm_posts_deleted.thread_title thr_subject,
298 frm_posts_deleted.forum_title top_name,
299 frm_posts_deleted.obj_id obj_id,
300 frm_notification.user_id user_id,
301 frm_posts_deleted.pos_display_user_id,
302 frm_posts_deleted.pos_usr_alias,
303 frm_posts_deleted.deleted_id,
304 frm_posts_deleted.post_date pos_date,
305 frm_posts_deleted.post_title pos_subject,
306 frm_posts_deleted.post_message pos_message
307
308 FROM frm_notification, frm_posts_deleted
309
310 WHERE ( frm_posts_deleted.obj_id = frm_notification.frm_id
311 OR frm_posts_deleted.thread_id = frm_notification.thread_id)
312 AND frm_posts_deleted.pos_display_user_id != frm_notification.user_id
313 AND frm_posts_deleted.is_thread_deleted = %s
314 ORDER BY frm_posts_deleted.post_date ASC',
315 array('integer'), array(1));
316 $numRows = $ilDB->numRows($res);
317 if($numRows > 0)
318 {
319 $this->logger->info(sprintf('Sending notifications for %s "deleted threads" events ...', $numRows));
320 $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_THREAD_DELETED);
321 if(count(self::$deleted_ids_cache) > 0)
322 {
323 $ilDB->manipulate('DELETE FROM frm_posts_deleted WHERE '. $ilDB->in('deleted_id', self::$deleted_ids_cache, false, 'integer'));
324 $this->logger->info('Deleted obsolete entries of table "frm_posts_deleted" ...');
325 }
326 $this->logger->info(sprintf('Sent notifications for deleted threads ...'));
327 }
328
329 $this->keepAlive();
330
331 /*** deleted posts ***/
332 $res = $ilDB->queryF('
333 SELECT frm_posts_deleted.thread_title thr_subject,
334 frm_posts_deleted.forum_title top_name,
335 frm_posts_deleted.obj_id obj_id,
336 frm_notification.user_id user_id,
337 frm_posts_deleted.pos_display_user_id,
338 frm_posts_deleted.pos_usr_alias,
339 frm_posts_deleted.deleted_id,
340 frm_posts_deleted.post_date pos_date,
341 frm_posts_deleted.post_title pos_subject,
342 frm_posts_deleted.post_message pos_message
343
344 FROM frm_notification, frm_posts_deleted
345
346 WHERE ( frm_posts_deleted.obj_id = frm_notification.frm_id
347 OR frm_posts_deleted.thread_id = frm_notification.thread_id)
348 AND frm_posts_deleted.pos_display_user_id != frm_notification.user_id
349 AND frm_posts_deleted.is_thread_deleted = %s
350 ORDER BY frm_posts_deleted.post_date ASC',
351 array('integer'), array(0));
352
353 $numRows = $ilDB->numRows($res);
354 if($numRows > 0)
355 {
356 $this->logger->info(sprintf('Sending notifications for %s "deleted postings" events ...', $numRows));
357 $this->sendCronForumNotification($res, ilForumMailNotification::TYPE_POST_DELETED);
358 if(count(self::$deleted_ids_cache) > 0)
359 {
360 $ilDB->manipulate('DELETE FROM frm_posts_deleted WHERE '. $ilDB->in('deleted_id', self::$deleted_ids_cache, false, 'integer'));
361 $this->logger->info('Deleted entries from table "frm_posts_deleted" ...');
362 }
363 $this->logger->info(sprintf('Sent notifications for deleted postings ...'));
364 }
365
366 $ilSetting->set('cron_forum_notification_last_date', $cj_start_date);
367
368 $mess = 'Sent '.$this->num_sent_messages.' messages.';
369
370 $this->logger->info($mess);
371 $this->logger->info('Finished forum notification job');
372
373 $result = new ilCronJobResult();
374 if($this->num_sent_messages)
375 {
377 $result->setMessage($mess);
378 };
379 $result->setStatus($status);
380 return $result;
381 }
382
387 protected function getRefIdsByObjId($a_obj_id)
388 {
389 if(!array_key_exists($a_obj_id, self::$ref_ids_by_obj_id))
390 {
391 self::$ref_ids_by_obj_id[$a_obj_id] = ilObject::_getAllReferences($a_obj_id);
392 }
393
394 return (array)self::$ref_ids_by_obj_id[$a_obj_id];
395 }
396
402 protected function getFirstAccessibleRefIdBUserAndObjId($a_user_id, $a_obj_id)
403 {
407 global $ilAccess;
408
409 if(!array_key_exists($a_user_id, self::$accessible_ref_ids_by_user))
410 {
411 self::$accessible_ref_ids_by_user[$a_user_id] = array();
412 }
413
414 if(!array_key_exists($a_obj_id, self::$accessible_ref_ids_by_user[$a_user_id]))
415 {
416 $accessible_ref_id = 0;
417 foreach($this->getRefIdsByObjId($a_obj_id) as $ref_id)
418 {
419 if($ilAccess->checkAccessOfUser($a_user_id, 'read', '', $ref_id))
420 {
421 $accessible_ref_id = $ref_id;
422 break;
423 }
424 }
425 self::$accessible_ref_ids_by_user[$a_user_id][$a_obj_id] = $accessible_ref_id;
426 }
427
428 return (int)self::$accessible_ref_ids_by_user[$a_user_id][$a_obj_id];
429 }
430
435 public function sendCronForumNotification($res, $notification_type)
436 {
440 global $ilDB;
441
442 include_once './Modules/Forum/classes/class.ilForumCronNotificationDataProvider.php';
443 include_once './Modules/Forum/classes/class.ilForumMailNotification.php';
444
445 while($row = $ilDB->fetchAssoc($res))
446 {
447 if($notification_type == ilForumMailNotification::TYPE_POST_DELETED
448 || $notification_type == ilForumMailNotification::TYPE_THREAD_DELETED)
449 {
450 // important! save the deleted_id to cache before proceeding getFirstAccessibleRefIdBUserAndObjId !
451 self::$deleted_ids_cache[$row['deleted_id']] = $row['deleted_id'];
452 }
453
454 $ref_id = $this->getFirstAccessibleRefIdBUserAndObjId($row['user_id'], $row['obj_id']);
455 if($ref_id < 1)
456 {
457 $this->logger->debug(sprintf(
458 'The recipient with id %s has no "read" permission for object with id %s',
459 $row['user_id'], $row['obj_id']
460 ));
461 continue;
462 }
463
464 $row['ref_id'] = $ref_id;
465
466 if($this->existsProviderObject($row['pos_pk']))
467 {
468 self::$providerObject[$row['pos_pk']]->addRecipient($row['user_id']);
469 }
470 else
471 {
472 $this->addProviderObject($row);
473 }
474 }
475
476 $usrIdsToPreload = array();
477 foreach (self::$providerObject as $provider) {
478 if ($provider->getPosAuthorId()) {
479 $usrIdsToPreload[$provider->getPosAuthorId()] = $provider->getPosAuthorId();
480 }
481 if ($provider->getPosDisplayUserId()) {
482 $usrIdsToPreload[$provider->getPosDisplayUserId()] = $provider->getPosDisplayUserId();
483 }
484 if ($provider->getPostUpdateUserId()) {
485 $usrIdsToPreload[$provider->getPostUpdateUserId()] = $provider->getPostUpdateUserId();
486 }
487 }
488
489 require_once 'Modules/Forum/classes/class.ilForumAuthorInformationCache.php';
490 ilForumAuthorInformationCache::preloadUserObjects(array_unique($usrIdsToPreload));
491
492 $i = 0;
493 foreach(self::$providerObject as $provider)
494 {
495 if ($i > 0 && ($i % self::KEEP_ALIVE_CHUNK_SIZE) == 0) {
496 $this->keepAlive();
497 }
498
499 $recipients = array_unique($provider->getCronRecipients());
500
501 $this->logger->info(sprintf(
502 'Trying to send forum notifications for posting id "%s", type "%s" and recipients: %s',
503 $provider->getPostId(), $notification_type, implode(', ', $recipients)
504 ));
505
506 $mailNotification = new ilForumMailNotification($provider, $this->logger);
507 $mailNotification->setIsCronjob(true);
508 $mailNotification->setType($notification_type);
509 $mailNotification->setRecipients($recipients);
510
511 $mailNotification->send();
512
513 $this->num_sent_messages += count($provider->getCronRecipients());
514 $this->logger->info(sprintf("Sent notifications ... "));
515
516 ++$i;
517 }
518
519 $this->resetProviderCache();
520 }
521
526 public function existsProviderObject($post_id)
527 {
528 if(isset(self::$providerObject[$post_id]))
529 {
530 return true;
531 }
532 return false;
533 }
534
538 private function addProviderObject($row)
539 {
540 $tmp_provider = new ilForumCronNotificationDataProvider($row);
541
542 self::$providerObject[$row['pos_pk']] = $tmp_provider;
543 self::$providerObject[$row['pos_pk']]->addRecipient($row['user_id']);
544 }
545
549 private function resetProviderCache()
550 {
551 self::$providerObject = array();
552 }
553
559 public function addToExternalSettingsForm($a_form_id, array &$a_fields, $a_is_active)
560 {
564 global $lng;
565
566 switch($a_form_id)
567 {
569 $a_fields['cron_forum_notification'] = $a_is_active ?
570 $lng->txt('enabled') :
571 $lng->txt('disabled');
572 break;
573 }
574 }
575
579 public function activationWasToggled($a_currently_active)
580 {
581 global $ilSetting;
582
583 // propagate cron-job setting to object setting
584 if((bool)$a_currently_active)
585 {
586 $ilSetting->set('forum_notification', 2);
587 }
588 else
589 {
590 $ilSetting->set('forum_notification', 1);
591 }
592 }
593
597 public function addCustomSettingsToForm(ilPropertyFormGUI $a_form)
598 {
602 global $lng;
603
604 $lng->loadLanguageModule('forum');
605
606 $max_notification_age = new ilNumberInputGUI($lng->txt('frm_max_notification_age'), 'max_notification_age');
607 $max_notification_age->setSize(5);
608 $max_notification_age->setSuffix($lng->txt('frm_max_notification_age_unit'));
609 $max_notification_age->setRequired(true);
610 $max_notification_age->allowDecimals(false);
611 $max_notification_age->setMinValue(1);
612 $max_notification_age->setInfo($lng->txt('frm_max_notification_age_info'));
613 $max_notification_age->setValue($this->settings->get('max_notification_age', 30));
614
615 $a_form->addItem($max_notification_age);
616 }
617
622 public function saveCustomSettings(ilPropertyFormGUI $a_form)
623 {
624 $this->settings->set('max_notification_age', $a_form->getInput('max_notification_age'));
625 return true;
626 }
627}
memory_get_usage(true)/1024/1024)
sprintf('%.4f', $callTime)
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
$result
An exception for terminatinating execution or to throw for unit testing.
Cron job result data container.
Cron job application base class.
addToExternalSettingsForm($a_form_id, array &$a_fields, $a_is_active)
Add external settings to form.
const SCHEDULE_TYPE_IN_HOURS
addCustomSettingsToForm(ilPropertyFormGUI $a_form)
Add custom settings to form.
static ping($a_job_id)
Keep cron job alive.
saveCustomSettings(ilPropertyFormGUI $a_form)
getDefaultScheduleValue()
Get schedule value.
hasAutoActivation()
Is to be activated on "installation".
hasFlexibleSchedule()
Can the schedule be configured?
This class represents a number property in a property form.
static _getAllReferences($a_id)
get all reference ids of object
This class represents a property form user interface.
addItem($a_item)
Add Item (Property, SectionHeader).
getInput($a_post_var, $ensureValidation=true)
Returns the value of a HTTP-POST variable, identified by the passed id.
ILIAS Setting Class.
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
global $lng
Definition: privfeed.php:17
global $ilSetting
Definition: privfeed.php:17
$ref_id
Definition: sahs_server.php:39
settings()
Definition: settings.php:2
global $ilDB