ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilSessionStatisticsGUI.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 {
23  private const int MODE_TODAY = 1;
24  private const int MODE_LAST_DAY = 2;
25  private const int MODE_LAST_WEEK = 3;
26  private const int MODE_LAST_MONTH = 4;
27  private const int MODE_DAY = 5;
28  private const int MODE_WEEK = 6;
29  private const int MODE_MONTH = 7;
30  private const int MODE_YEAR = 8;
31 
32  private const int SCALE_DAY = 1;
33  private const int SCALE_WEEK = 2;
34  private const int SCALE_MONTH = 3;
35  private const int SCALE_YEAR = 4;
36  private const int SCALE_PERIODIC_WEEK = 5;
37 
38  private const string REQUEST_SMD = 'smd';
39  private const string REQUEST_SMM = 'smm';
40  private const string REQUEST_SST = 'sst';
41  private const string REQUEST_STO = 'sto';
42  private const string REQUEST_REF = 'ref_id';
43 
44  private ilCtrl $ilCtrl;
45  private ilTabsGUI $ilTabs;
46  private ilLanguage $lng;
50  private ilAccess $access;
52  private ilObjUser $user;
53  private ilLogger $logger;
54 
55  private int $ref_id = -1;
56  private ?int $smd = null;
57  private ?string $smm = null;
58  private ?string $sst = null;
59  private ?string $sto = null;
60 
61  public function __construct()
62  {
63  global $DIC;
64 
65  $this->ilCtrl = $DIC->ctrl();
66  $this->ilTabs = $DIC->tabs();
67  $this->lng = $DIC->language();
68  $this->tpl = $DIC->ui()->mainTemplate();
69  $this->toolbar = $DIC->toolbar();
70  $this->settings = $DIC->settings();
71  $this->access = $DIC->access();
72  $this->clientIniFile = $DIC->clientIni();
73  $this->user = $DIC->user();
74  $this->logger = $DIC->logger()->auth();
75 
76  $http = $DIC->http();
77  $kindlyTo = $DIC->refinery()->kindlyTo();
78  if ($http->request()->getMethod() === 'POST') {
79  if ($http->wrapper()->post()->has(self::REQUEST_SMD)) {
80  $this->smd = $http->wrapper()->post()->retrieve(self::REQUEST_SMD, $kindlyTo->int());
81  }
82  if ($http->wrapper()->post()->has(self::REQUEST_SMM)) {
83  $this->smm = $http->wrapper()->post()->retrieve(self::REQUEST_SMM, $kindlyTo->string());
84  }
85  if ($http->wrapper()->post()->has(self::REQUEST_STO)) {
86  $this->sto = $http->wrapper()->post()->retrieve(self::REQUEST_STO, $kindlyTo->string());
87  }
88  if ($http->wrapper()->post()->has(self::REQUEST_SST)) {
89  $this->sst = $http->wrapper()->post()->retrieve(self::REQUEST_SST, $kindlyTo->string());
90  }
91  } else {
92  if ($http->wrapper()->query()->has(self::REQUEST_SMD)) {
93  $this->smd = $http->wrapper()->query()->retrieve(self::REQUEST_SMD, $kindlyTo->int());
94  }
95  if ($http->wrapper()->query()->has(self::REQUEST_SMM)) {
96  $this->smm = $http->wrapper()->query()->retrieve(self::REQUEST_SMM, $kindlyTo->string());
97  }
98  if ($http->wrapper()->query()->has(self::REQUEST_STO)) {
99  $this->sto = $http->wrapper()->query()->retrieve(self::REQUEST_STO, $kindlyTo->string());
100  }
101  if ($http->wrapper()->query()->has(self::REQUEST_SST)) {
102  $this->sst = $http->wrapper()->query()->retrieve(self::REQUEST_SST, $kindlyTo->string());
103  }
104  }
105  if ($http->wrapper()->query()->has(self::REQUEST_REF)) {
106  $this->ref_id = $http->wrapper()->query()->retrieve(self::REQUEST_REF, $kindlyTo->int());
107  }
108  }
109 
110  public function executeCommand(): bool
111  {
112  $this->setSubTabs();
113 
114  switch ($this->ilCtrl->getNextClass()) {
115  default:
116  $cmd = $this->ilCtrl->getCmd('current');
117  $this->$cmd();
118  }
119 
120  return true;
121  }
122 
123  protected function setSubTabs(): void
124  {
125  $this->ilTabs->addSubTab(
126  'current',
127  $this->lng->txt('trac_current_system_load'),
128  $this->ilCtrl->getLinkTarget($this, 'current')
129  );
130  $this->ilTabs->addSubTab(
131  'short',
132  $this->lng->txt('trac_short_system_load'),
133  $this->ilCtrl->getLinkTarget($this, 'short')
134  );
135  $this->ilTabs->addSubTab(
136  'long',
137  $this->lng->txt('trac_long_system_load'),
138  $this->ilCtrl->getLinkTarget($this, 'long')
139  );
140  $this->ilTabs->addSubTab(
141  'periodic',
142  $this->lng->txt('trac_periodic_system_load'),
143  $this->ilCtrl->getLinkTarget($this, 'periodic')
144  );
145  }
146 
147  protected function current(bool $a_export = false): void
148  {
149  $this->ilTabs->activateSubTab('current');
150 
151  // current mode
152  if (!$this->smd) {
153  $mode = self::MODE_TODAY;
154  } else {
155  $mode = $this->smd;
156  }
157 
158  // current measure
159  if (!$this->smm) {
160  $measure = 'avg';
161  } else {
162  $measure = $this->smm;
163  }
164 
165  switch ($mode) {
166  default:
167  case self::MODE_TODAY:
168  $time_from = strtotime('today');
169  $time_to = strtotime('tomorrow') - 1;
170  $scale = self::SCALE_DAY;
171  break;
172 
173  case self::MODE_LAST_DAY:
174  $time_to = time();
175  $time_from = $time_to - 60 * 60 * 24;
176  $scale = self::SCALE_DAY;
177  break;
178 
179  case self::MODE_LAST_WEEK:
180  $time_to = time();
181  $time_from = $time_to - 60 * 60 * 24 * 7;
182  $scale = self::SCALE_WEEK;
183  break;
184 
185  case self::MODE_LAST_MONTH:
186  $time_to = time();
187  $time_from = $time_to - 60 * 60 * 24 * 30;
188  $scale = self::SCALE_MONTH;
189  break;
190  }
191 
192  $mode_options = [
193  self::MODE_TODAY => $this->lng->txt('trac_session_statistics_mode_today'),
194  self::MODE_LAST_DAY => $this->lng->txt('trac_session_statistics_mode_last_day'),
195  self::MODE_LAST_WEEK => $this->lng->txt('trac_session_statistics_mode_last_week'),
196  self::MODE_LAST_MONTH => $this->lng->txt('trac_session_statistics_mode_last_month')
197  ];
198 
199  $title = $this->lng->txt('trac_current_system_load') . ' - ' . $mode_options[$mode];
200  $data = $this->buildData($time_from, $time_to, $title);
201 
202  if (!$a_export) {
203  // toolbar
204  $this->toolbar->setFormAction($this->ilCtrl->getFormAction($this, 'current'));
205 
206  $mode_selector = new ilSelectInputGUI('&nbsp;' . $this->lng->txt('trac_scale'), 'smd');
207  $mode_selector->setOptions($mode_options);
208  $mode_selector->setValue($mode);
209  $this->toolbar->addInputItem($mode_selector, true);
210 
211  $measure_options = [
212  'avg' => $this->lng->txt('trac_session_active_avg'),
213  'min' => $this->lng->txt('trac_session_active_min'),
214  'max' => $this->lng->txt('trac_session_active_max')
215  ];
216 
217  $measure_selector = new ilSelectInputGUI('&nbsp;' . $this->lng->txt('trac_measure'), 'smm');
218  $measure_selector->setOptions($measure_options);
219  $measure_selector->setValue($measure);
220  $this->toolbar->addInputItem($measure_selector, true);
221 
222  $this->toolbar->addFormButton($this->lng->txt('ok'), 'current');
223 
224  if (count($data['active'])) {
225  $this->toolbar->addSeparator();
226  $this->toolbar->addFormButton($this->lng->txt('export'), 'currentExport');
227  }
228 
229  $this->tpl->setContent($this->render($data, $scale, $measure));
230 
231  $this->tpl->setLeftContent($this->renderCurrentBasics());
232  } else {
233  $this->exportCSV($data, $scale);
234  }
235  }
236 
237  protected function currentExport(): void
238  {
239  $this->current(true);
240  }
241 
245  protected function importDate(string $a_incoming, ?int $a_default = null)
246  {
247  if (!$a_default) {
248  $a_default = time();
249  }
250 
251  $parsed = ilCalendarUtil::parseIncomingDate($a_incoming);
252  return $parsed
253  ? $parsed->get(IL_CAL_UNIX)
254  : $a_default;
255  }
256 
257  protected function short(bool $a_export = false): void
258  {
259  $this->ilTabs->activateSubTab('short');
260 
261  //TODO validate input
262  // current start
263  $time_to = $this->importDate((string) $this->sst);
264 
265  // current mode
266  if (!$this->smd) {
267  $mode = self::MODE_DAY;
268  } else {
269  $mode = $this->smd;
270  }
271 
272  // current measure
273  if (!$this->smm) {
274  $measure = 'avg';
275  } else {
276  $measure = $this->smm;
277  }
278 
279  switch ($mode) {
280  default:
281  case self::MODE_DAY:
282  $time_from = $time_to - 60 * 60 * 24;
283  $scale = self::SCALE_DAY;
284  break;
285 
286  case self::MODE_WEEK:
287  $time_from = $time_to - 60 * 60 * 24 * 7;
288  $scale = self::SCALE_WEEK;
289  break;
290  }
291 
292  $mode_options = [
293  self::MODE_DAY => $this->lng->txt('trac_session_statistics_mode_day'),
294  self::MODE_WEEK => $this->lng->txt('trac_session_statistics_mode_week')
295  ];
296 
297  $title = $this->lng->txt('trac_short_system_load') . ' - ' . $mode_options[$mode];
298  $data = $this->buildData($time_from, $time_to, $title);
299 
300  if (!$a_export) {
301  // toolbar
302  $this->toolbar->setFormAction($this->ilCtrl->getFormAction($this, 'short'));
303 
304  $start_selector = new ilDateTimeInputGUI($this->lng->txt('trac_end_at'), 'sst');
305  $start_selector->setDate(new ilDate($time_to, IL_CAL_UNIX));
306  $this->toolbar->addInputItem($start_selector, true);
307 
308  $mode_selector = new ilSelectInputGUI('&nbsp;' . $this->lng->txt('trac_scale'), 'smd');
309  $mode_selector->setOptions($mode_options);
310  $mode_selector->setValue($mode);
311  $this->toolbar->addInputItem($mode_selector, true);
312 
313  $measure_options = [
314  'avg' => $this->lng->txt('trac_session_active_avg'),
315  'min' => $this->lng->txt('trac_session_active_min'),
316  'max' => $this->lng->txt('trac_session_active_max')
317  ];
318 
319  $measure_selector = new ilSelectInputGUI('&nbsp;' . $this->lng->txt('trac_measure'), 'smm');
320  $measure_selector->setOptions($measure_options);
321  $measure_selector->setValue($measure);
322  $this->toolbar->addInputItem($measure_selector, true);
323 
324  $this->toolbar->addFormButton($this->lng->txt('ok'), 'short');
325 
326  if (count($data['active'])) {
327  $this->toolbar->addSeparator();
328  $this->toolbar->addFormButton($this->lng->txt('export'), 'shortExport');
329  }
330 
331  $this->tpl->setContent($this->render($data, $scale, $measure));
332  } else {
333  $this->exportCSV($data, $scale);
334  }
335  }
336 
337  protected function shortExport(): void
338  {
339  $this->short(true);
340  }
341 
342  protected function long($a_export = false): void
343  {
344  $this->ilTabs->activateSubTab('long');
345 
346  // current start
347  //TODO validate input
348  $time_to = $this->importDate((string) $this->sst);
349 
350  // current mode
351  if (!$this->smd) {
352  $mode = self::MODE_WEEK;
353  } else {
354  $mode = $this->smd;
355  }
356 
357  switch ($mode) {
358  default:
359  case self::MODE_WEEK:
360  $time_from = $time_to - 60 * 60 * 24 * 7;
361  $scale = self::SCALE_WEEK;
362  break;
363 
364  case self::MODE_MONTH:
365  $time_from = $time_to - 60 * 60 * 24 * 30;
366  $scale = self::SCALE_MONTH;
367  break;
368 
369  case self::MODE_YEAR:
370  $time_from = $time_to - 60 * 60 * 24 * 365;
371  $scale = self::SCALE_YEAR;
372  break;
373  }
374 
375  $mode_options = [
376  self::MODE_WEEK => $this->lng->txt('trac_session_statistics_mode_week'),
377  self::MODE_MONTH => $this->lng->txt('trac_session_statistics_mode_month'),
378  self::MODE_YEAR => $this->lng->txt('trac_session_statistics_mode_year')
379  ];
380 
381  $title = $this->lng->txt('trac_long_system_load') . ' - ' . $mode_options[$mode];
382  $data = $this->buildData($time_from, $time_to, $title);
383 
384  if (!$a_export) {
385  // toolbar
386  $this->toolbar->setFormAction($this->ilCtrl->getFormAction($this, 'long'));
387 
388  $start_selector = new ilDateTimeInputGUI($this->lng->txt('trac_end_at'), 'sst');
389  $start_selector->setDate(new ilDate($time_to, IL_CAL_UNIX));
390  $this->toolbar->addInputItem($start_selector, true);
391 
392  $mode_selector = new ilSelectInputGUI('&nbsp;' . $this->lng->txt('trac_scale'), 'smd');
393  $mode_selector->setOptions($mode_options);
394  $mode_selector->setValue($mode);
395  $this->toolbar->addInputItem($mode_selector, true);
396 
397  $this->toolbar->addFormButton($this->lng->txt('ok'), 'long');
398 
399  if (count($data['active'])) {
400  $this->toolbar->addSeparator();
401  $this->toolbar->addFormButton($this->lng->txt('export'), 'longExport');
402  }
403 
404  $this->tpl->setContent($this->render($data, $scale));
405  } else {
406  $this->exportCSV($data, $scale);
407  }
408  }
409 
410  protected function longExport(): void
411  {
412  $this->long(true);
413  }
414 
415  protected function periodic($a_export = false): void
416  {
417  $this->ilTabs->activateSubTab('periodic');
418 
419  //TODO validate input
420  // current start
421  $time_to = $this->importDate((string) $this->sst);
422 
423  // current end
424  $time_from = $this->importDate((string) $this->sto, strtotime('-7 days'));
425 
426  // mixed up dates?
427  if ($time_to < $time_from) {
428  $tmp = $time_to;
429  $time_to = $time_from;
430  $time_from = $tmp;
431  }
432 
433  $title = $this->lng->txt('trac_periodic_system_load');
434  $data = $this->buildData($time_from, $time_to, $title);
435 
436  if (!$a_export) {
437  // toolbar
438  $this->toolbar->setFormAction($this->ilCtrl->getFormAction($this, 'periodic'));
439 
440  $end_selector = new ilDateTimeInputGUI($this->lng->txt('trac_begin_at'), 'sto');
441  $end_selector->setDate(new ilDate($time_from, IL_CAL_UNIX));
442  $this->toolbar->addInputItem($end_selector, true);
443 
444  $start_selector = new ilDateTimeInputGUI($this->lng->txt('trac_end_at'), 'sst');
445  $start_selector->setDate(new ilDate($time_to, IL_CAL_UNIX));
446  $this->toolbar->addInputItem($start_selector, true);
447 
448  $this->toolbar->addFormButton($this->lng->txt('ok'), 'periodic');
449 
450  if (count($data['active'])) {
451  $this->toolbar->addSeparator();
452  $this->toolbar->addFormButton($this->lng->txt('export'), 'periodicExport');
453  }
454 
455  $this->tpl->setContent($this->render($data, self::SCALE_PERIODIC_WEEK));
456  } else {
457  $this->exportCSV($data, self::SCALE_PERIODIC_WEEK);
458  }
459  }
460 
461  protected function periodicExport(): void
462  {
463  $this->periodic(true);
464  }
465 
466  protected function renderCurrentBasics(): string
467  {
468  // basic data - not time related
469 
471 
473 
474 
475  // build left column
476 
477  $left = new ilTemplate('tpl.session_statistics_left.html', true, true, 'components/ILIAS/Authentication');
478 
479  $left->setVariable('CAPTION_CURRENT', $this->lng->txt('users_online'));
480  $left->setVariable('VALUE_CURRENT', $active);
481 
482  $left->setVariable('CAPTION_LAST_AGGR', $this->lng->txt('trac_last_aggregation'));
483  $left->setVariable('VALUE_LAST_AGGR', ilDatePresentation::formatDate($last_aggr));
484 
485  // sync button
486  if ($this->access->checkAccess('write', '', $this->ref_id)) {
487  $left->setVariable('URL_SYNC', $this->ilCtrl->getFormAction($this, 'adminSync'));
488  $left->setVariable('CMD_SYNC', 'adminSync');
489  $left->setVariable('TXT_SYNC', $this->lng->txt('trac_sync_session_stats'));
490  }
491 
492  return $left->get();
493  }
494 
495  protected function buildData(int $a_time_from, int $a_time_to, string $a_title): array
496  {
497  // basic data - time related
498 
499  $counters = ilSessionStatistics::getNumberOfSessionsByType($a_time_from, $a_time_to);
500  $opened = (int) $counters['opened'];
501  unset($counters['opened']);
502 
503 
504  // build center column
505 
506  $data = [];
507 
509  $data['title'] = $a_title . ' (' .
511  new ilDateTime($a_time_from, IL_CAL_UNIX),
512  new ilDateTime($a_time_to, IL_CAL_UNIX)
513  ) . ')';
514 
515  $data['opened'] = [$this->lng->txt('trac_sessions_opened'), $opened];
516  $data['closed'] = [$this->lng->txt('trac_sessions_closed'), array_sum($counters)];
517  foreach ($counters as $type => $counter) {
518  $data['closed_details'][] = [$this->lng->txt('trac_' . $type), (int) $counter];
519  }
520 
521  $data['active'] = ilSessionStatistics::getActiveSessions($a_time_from, $a_time_to);
522  $this->logger->debug('Data to plot: ' . var_export($data, true));
523  return $data;
524  }
525 
526  protected function render(array $a_data, int $a_scale, ?string $a_measure = null): string
527  {
528  $center = new ilTemplate('tpl.session_statistics_center.html', true, true, 'components/ILIAS/Authentication');
529 
530  foreach ($a_data as $idx => $item) {
531  switch ($idx) {
532  case 'active':
533  case 'title':
534  // nothing to do
535  break;
536 
537  case 'closed_details':
538  $center->setCurrentBlock('closed_details');
539  foreach ($item as $detail) {
540  $center->setVariable('CAPTION_CLOSED_DETAILS', $detail[0]);
541  $center->setVariable('VALUE_CLOSED_DETAILS', $detail[1]);
542  $center->parseCurrentBlock();
543  }
544  break;
545 
546  default:
547  $tpl_var = strtoupper($idx);
548  $center->setVariable('CAPTION_' . $tpl_var, $item[0]);
549  $center->setVariable('VALUE_' . $tpl_var, $item[1]);
550  break;
551  }
552  }
553 
554  if ($a_data['active']) {
555  $center->setVariable('CHART', $this->getChart($a_data['active'], $a_data['title'], $a_scale, $a_measure));
556  } else {
557  $this->tpl->setOnScreenMessage('info', $this->lng->txt('trac_session_statistics_no_data'));
558  }
559 
560  return $center->get();
561  }
562 
566  protected function getChart(
567  array $a_data,
568  string $a_title,
569  int $a_scale = self::SCALE_DAY,
570  ?string $a_measure = null
571  ): string {
572  $chart = ilChart::getInstanceByType(ilChart::TYPE_GRID, 'objstacc');
573  $chart->setSize('700', '500');
574  $chart->setYAxisToInteger(true);
575 
576  $legend = new ilChartLegend();
577  $chart->setLegend($legend);
578 
579  if (!$a_measure) {
580  $measures = ['min', 'avg', 'max'];
581  } else {
582  $measures = [$a_measure];
583  }
584 
585  $colors_map = [
586  'min' => '#00cc00',
587  'avg' => '#0000cc',
588  'max' => '#cc00cc'
589  ];
590 
591  $colors = $act_line = [];
592  foreach ($measures as $measure) {
593  $act_line[$measure] = $chart->getDataInstance(ilChartGrid::DATA_LINES);
594  $act_line[$measure]->setLineSteps(true);
595  $act_line[$measure]->setLabel($this->lng->txt('trac_session_active_' . $measure));
596  $colors[] = $colors_map[$measure];
597  }
598 
599  $chart->setColors($colors);
600 
601  $chart_data = $this->adaptDataToScale($a_scale, $a_data);
602 
603  $scale = ceil(count($chart_data) / 5);
604  $labels = [];
605  foreach ($chart_data as $idx => $item) {
606  $date = $item['slot_begin'];
607 
608  if ($a_scale === self::SCALE_PERIODIC_WEEK || !($idx % ceil($scale))) {
609  switch ($a_scale) {
610  case self::SCALE_DAY:
611  $labels[$date] = date('H:i', $date);
612  break;
613 
614  case self::SCALE_WEEK:
615  $labels[$date] = date('d.m. H', $date) . 'h';
616  break;
617 
618  case self::SCALE_MONTH:
619  $labels[$date] = date('d.m.', $date);
620  break;
621 
622  case self::SCALE_YEAR:
623  $labels[$date] = date('Y-m', $date);
624  break;
625 
626  case self::SCALE_PERIODIC_WEEK:
627  $day = substr((string) $date, 0, 1);
628  $hour = substr((string) $date, 1, 2);
629  $min = substr((string) $date, 3, 2);
630 
631  // build ascending scale from day values
632  $day_value = ($day - 1) * 60 * 60 * 24;
633  $date = $day_value + $hour * 60 * 60 + $min * 60;
634 
635  // 6-hour interval labels
636  if ((!isset($old_hour) || $hour != $old_hour) && $hour && $hour % 6 == 0) {
637  $labels[$date] = $hour;
638  $old_hour = $hour;
639  }
640  // day label
641  if (!isset($old_day) || $day != $old_day) {
642  $labels[$date] = ilCalendarUtil::_numericDayToString((int) $day, false);
643  $old_day = $day;
644  }
645  break;
646  }
647  }
648 
649  foreach ($measures as $measure) {
650  $value = (int) $item['active_' . $measure];
651  $act_line[$measure]->addPoint($date, $value);
652  }
653  }
654 
655  foreach ($act_line as $line) {
656  $chart->addData($line);
657  }
658 
659  $chart->setTicks($labels, null, true);
660 
661  return $chart->getHTML();
662  }
663 
664  protected function adaptDataToScale(int $a_scale, array $a_data): array
665  {
666  // can we use original data?
667  switch ($a_scale) {
668  case self::SCALE_DAY:
669  // 96 values => ok
670  // fallthrough
671 
672  case self::SCALE_WEEK:
673  // 672 values => ok
674  return $a_data;
675  }
676 
677  $tmp = [];
678  foreach ($a_data as $item) {
679  $date_parts = getdate($item['slot_begin']);
680 
681  // aggregate slots for scale
682  switch ($a_scale) {
683  default:
684  case self::SCALE_MONTH:
685  // aggregate to hours => 720 values
686  $slot = mktime($date_parts['hours'], 0, 0, $date_parts['mon'], $date_parts['mday'], $date_parts['year']);
687  break;
688 
689  case self::SCALE_YEAR:
690  // aggregate to days => 365 values
691  $slot = mktime(0, 0, 1, $date_parts['mon'], $date_parts['mday'], $date_parts['year']);
692  break;
693 
694  case self::SCALE_PERIODIC_WEEK:
695  // aggregate to weekdays => 672 values
696  $day = $date_parts['wday'];
697  if (!$day) {
698  $day = 7;
699  }
700  $slot = $day . date('His', $item['slot_begin']);
701  break;
702  }
703 
704  // process minx/max, prepare avg
705  foreach ($item as $id => $value) {
706  switch (substr((string) $id, -3)) {
707  case 'min':
708  if (!isset($tmp[$slot][$id]) || $value < $tmp[$slot][$id]) {
709  $tmp[$slot][$id] = $value;
710  }
711  break;
712 
713  case 'max':
714  if (!isset($tmp[$slot][$id]) || $value > $tmp[$slot][$id]) {
715  $tmp[$slot][$id] = $value;
716  }
717  break;
718 
719  case 'avg':
720  $tmp[$slot][$id][] = $value;
721  break;
722  }
723  }
724  }
725 
726  foreach ($tmp as $slot => $attr) {
727  $tmp[$slot]['active_avg'] = (int) round(array_sum($attr['active_avg']) / count($attr['active_avg']));
728  $tmp[$slot]['slot_begin'] = $slot;
729  }
730  ksort($tmp);
731  return array_values($tmp);
732  }
733 
734  protected function adminSync(): void
735  {
736  // see ilSession::_writeData()
737  $now = time();
740 
741  $this->tpl->setOnScreenMessage('success', $this->lng->txt('trac_sync_session_stats_success'), true);
742  $this->ilCtrl->redirect($this);
743  }
744 
745  protected function exportCSV(array $a_data, $a_scale): never
746  {
748 
749  $csv = new ilCSVWriter();
750  $csv->setSeparator(';');
751 
752  $now = time();
753 
754  // meta
755  $meta = [
756  $this->lng->txt('trac_name_of_installation') => $this->clientIniFile->readVariable('client', 'name'),
757  $this->lng->txt('trac_report_date') => ilDatePresentation::formatDate(new ilDateTime($now, IL_CAL_UNIX)),
758  $this->lng->txt('trac_report_owner') => $this->user->getFullName(),
759  ];
760  foreach ($a_data as $idx => $item) {
761  switch ($idx) {
762  case 'title':
763  $meta[$this->lng->txt('title')] = $item;
764  break;
765 
766  case 'active':
767  // nothing to do
768  break;
769 
770  case 'closed_details':
771  foreach ($item as $detail) {
772  $meta[$a_data['closed'][0] . ' - ' . $detail[0]] = $detail[1];
773  }
774  break;
775 
776  default:
777  $meta[$item[0]] = $item[1];
778  break;
779  }
780  }
781  foreach ($meta as $caption => $value) {
782  $csv->addColumn(strip_tags((string) $caption));
783  $csv->addColumn(strip_tags((string) $value));
784  $csv->addRow();
785  }
786  $csv->addRow();
787 
788  // aggregate data
789  $aggr_data = $this->adaptDataToScale($a_scale, $a_data['active']);
790 
791  // header
792  $first = $aggr_data;
793  $first = array_keys(array_shift($first));
794  foreach ($first as $column) {
795  // split weekday and time slot again
796  if ($a_scale === self::SCALE_PERIODIC_WEEK && $column === 'slot_begin') {
797  $csv->addColumn('weekday');
798  $csv->addColumn('time');
799  } else {
800  $csv->addColumn(strip_tags((string) $column));
801  }
802  }
803  $csv->addRow();
804 
805  // data
806  foreach ($aggr_data as $row) {
807  foreach ($row as $column => $value) {
808  if (is_array($value)) {
809  $value = implode(', ', $value);
810  }
811  switch ($column) {
812  case 'slot_begin':
813  // split weekday and time slot again
814  if ($a_scale === self::SCALE_PERIODIC_WEEK) {
815  $csv->addColumn(ilCalendarUtil::_numericDayToString((int) substr((string) $value, 0, 1)));
816  $value = substr((string) $value, 1, 2) . ':' . substr((string) $value, 3, 2);
817  break;
818  }
819  // fallthrough
820 
821  // no break
822  case 'slot_end':
823  $value = date('d.m.Y H:i', $value);
824  break;
825  }
826  $csv->addColumn(strip_tags((string) $value));
827  }
828  $csv->addRow();
829  }
830 
831  // send
832  $filename = 'session_statistics_' . date('Ymd', $now) . '.csv';
833  header('Content-type: text/comma-separated-values');
834  header('Content-Disposition: attachment; filename="' . $filename . '"');
835  header('Expires: 0');
836  header('Cache-Control: must-revalidate, post-check=0,pre-check=0');
837  header('Pragma: public');
838  echo $csv->getCSVString();
839  exit();
840  }
841 }
static array static setUseRelativeDates(bool $a_status)
set use relative dates
exportCSV(array $a_data, $a_scale)
static getNumberOfSessionsByType(int $a_from, int $a_to)
Get session counters by type (opened, closed)
static parseIncomingDate($value, bool $add_time=false)
Try to parse incoming value to date object.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a selection list property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setOptions(array $a_options)
$http
Definition: deliver.php:30
const IL_CAL_UNIX
static _destroyExpiredSessions()
Destroy expired sessions.
static aggretateRaw(int $a_now)
Aggregate raw session data (older than given time)
adaptDataToScale(int $a_scale, array $a_data)
This class represents a date/time property in a property form.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
ilGlobalTemplateInterface $tpl
static _numericDayToString(int $a_day, bool $a_long=true, ?ilLanguage $lng=null)
static getLastAggregation()
Get timestamp of last aggregation.
importDate(string $a_incoming, ?int $a_default=null)
global $DIC
Definition: shib_login.php:26
setDate(?ilDateTime $a_date=null)
set date E.g $dt_form->setDate(new ilDateTime(time(),IL_CAL_UTC)); or $dt_form->setDate(new ilDateTim...
exit
const TYPE_GRID
$filename
Definition: buildRTE.php:78
render(array $a_data, int $a_scale, ?string $a_measure=null)
static getExistingSessionCount(array $a_types)
static array $session_types_controlled
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
getChart(array $a_data, string $a_title, int $a_scale=self::SCALE_DAY, ?string $a_measure=null)
Build chart for active sessions.
header()
expected output: > ILIAS shows the rendered Component.
Definition: header.php:29
buildData(int $a_time_from, int $a_time_to, string $a_title)
static formatPeriod(ilDateTime $start, ilDateTime $end, bool $a_skip_starting_day=false, ?ilObjUser $user=null)
Format a period of two dates Shows: 14.
static getInstanceByType(int $a_type, string $a_id)