ILIAS  release_8 Revision v8.23
class.ilCronFinishUnfinishedTestPasses.php
Go to the documentation of this file.
1 <?php
2 
24 {
28  protected $log;
29 
30  protected ilLanguage $lng;
31  protected ilDBInterface $db;
33  protected int $now;
34  protected array $unfinished_passes;
35  protected array $test_ids;
36  protected array $test_ending_times;
38 
39  public function __construct()
40  {
41  global $DIC;
42 
43  $this->log = ilLoggerFactory::getLogger('tst');
44  $this->lng = $DIC['lng'];
45  $this->lng->loadLanguageModule('assessment');
46  $this->db = $DIC->database();
47  $this->obj_data_cache = $DIC['ilObjDataCache'];
48  $this->now = time();
49  $this->unfinished_passes = array();
50  $this->test_ids = array();
51  $this->test_ending_times = array();
52 
53  require_once 'Modules/Test/classes/class.ilTestProcessLockerFactory.php';
54  $this->processLockerFactory = new ilTestProcessLockerFactory(
55  new ilSetting('assessment'),
56  $this->db
57  );
58  }
59 
60  public function getId(): string
61  {
62  return 'finish_unfinished_passes';
63  }
64 
65  public function getTitle(): string
66  {
67  global $DIC;
68  $lng = $DIC['lng'];
69 
70  return $lng->txt("finish_unfinished_passes");
71  }
72 
73  public function getDescription(): string
74  {
75  global $DIC;
76  $lng = $DIC['lng'];
77 
78  return $lng->txt("finish_unfinished_passes_desc");
79  }
80 
81  public function getDefaultScheduleType(): int
82  {
83  return self::SCHEDULE_TYPE_DAILY;
84  }
85 
86  public function getDefaultScheduleValue(): int
87  {
88  return 1;
89  }
90 
91  public function hasAutoActivation(): bool
92  {
93  return false;
94  }
95 
96  public function hasFlexibleSchedule(): bool
97  {
98  return true;
99  }
100 
101  public function hasCustomSettings(): bool
102  {
103  return true;
104  }
105 
106  public function run(): ilCronJobResult
107  {
108  $this->log->info('start inf cronjob...');
109 
110  $result = new ilCronJobResult();
111 
113  if (count($this->unfinished_passes) > 0) {
114  $this->log->info('found ' . count($this->unfinished_passes) . ' unfinished passes starting analyses.');
116  $this->processPasses();
117  } else {
118  $this->log->info('No unfinished passes found.');
119  }
120 
121  $result->setStatus(ilCronJobResult::STATUS_OK);
122 
123  $this->log->info(' ...finishing cronjob.');
124 
125  return $result;
126  }
127 
128  protected function gatherUsersWithUnfinishedPasses(): void
129  {
130  $query = "SELECT tst_active.active_id,
131  tst_active.tries,
132  tst_active.user_fi usr_id,
133  tst_active.test_fi test_fi,
134  usr_data.login,
135  usr_data.lastname,
136  usr_data.firstname,
137  tst_active.submitted test_finished,
138  usr_data.matriculation,
139  usr_data.active,
140  tst_active.lastindex,
141  tst_active.last_started_pass last_started
142  FROM tst_active
143  LEFT JOIN usr_data
144  ON tst_active.user_fi = usr_data.usr_id
145  WHERE IFNULL(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass
146  ";
147  $result = $this->db->query($query);
148  while ($row = $this->db->fetchAssoc($result)) {
149  $this->unfinished_passes[] = $row;
150  $this->test_ids[] = $row['test_fi'];
151  }
152  }
153 
154  protected function getTestsFinishAndProcessingTime(): void
155  {
156  $query = 'SELECT test_id, obj_fi, ending_time, ending_time_enabled, processing_time, enable_processing_time FROM tst_tests WHERE ' .
157  $this->db->in('test_id', $this->test_ids, false, 'integer');
158  $result = $this->db->query($query);
159  while ($row = $this->db->fetchAssoc($result)) {
160  $this->test_ending_times[$row['test_id']] = $row;
161  }
162  $this->log->info('Gathered data for ' . count($this->test_ids) . ' test id(s) => (' . implode(',', $this->test_ids) . ')');
163  }
164 
165  protected function processPasses(): void
166  {
167  $now = time();
168  foreach ($this->unfinished_passes as $key => $data) {
169  $test_id = $data['test_fi'];
170  $can_not_be_finished = true;
171  if (array_key_exists($test_id, $this->test_ending_times)) {
172  if ($this->test_ending_times[$test_id]['ending_time_enabled'] == 1) {
173  $this->log->info('Test (' . $test_id . ') has ending time (' . $this->test_ending_times[$test_id]['ending_time'] . ')');
174  $ending_time = $this->test_ending_times[$test_id]['ending_time'];
175  if ($ending_time < $now) {
176  $this->finishPassForUser($data['active_id'], $this->test_ending_times[$test_id]['obj_fi']);
177  $can_not_be_finished = false;
178  } else {
179  $this->log->info('Test (' . $test_id . ') ending time (' . $this->test_ending_times[$test_id]['ending_time'] . ') > now (' . $now . ') is not reached.');
180  }
181  } else {
182  $this->log->info('Test (' . $test_id . ') has no ending time.');
183  }
184  if ($this->test_ending_times[$test_id]['enable_processing_time'] == 1) {
185  $this->log->info('Test (' . $test_id . ') has processing time (' . $this->test_ending_times[$test_id]['processing_time'] . ')');
186  $obj_id = $this->test_ending_times[$test_id]['obj_fi'];
187  if(ilObject::_exists($obj_id)) {
188  $test_obj = new ilObjTest($obj_id, false);
189  $startingTime = $test_obj->getStartingTimeOfUser($data['active_id']);
190  $max_processing_time = $test_obj->isMaxProcessingTimeReached($startingTime, $data['active_id']);
191  if ($max_processing_time) {
192  $this->log->info('Max Processing time reached for user id (' . $data['usr_id'] . ') so test with active id (' . $data['active_id'] . ') will be finished.');
193  $this->finishPassForUser($data['active_id'], $this->test_ending_times[$test_id]['obj_fi']);
194  $can_not_be_finished = false;
195  } else {
196  $this->log->info('Max Processing time not reached for user id (' . $data['usr_id'] . ') in test with active id (' . $data['active_id'] . '). Starting time: ' . $startingTime . ' Processing time: ' . $test_obj->getProcessingTime() . ' / ' . $test_obj->getProcessingTimeInSeconds() . 's');
197  }
198  } else {
199  $this->log->info('Test object with id (' . $obj_id . ') does not exist.');
200  }
201  } else {
202  $this->log->info('Test (' . $test_id . ') has no processing time.');
203  }
204 
205  if ($can_not_be_finished) {
206  $this->log->info('Test session with active id (' . $data['active_id'] . ') can not be finished by this cron job.');
207  }
208  }
209  }
210  }
211 
212  protected function finishPassForUser($active_id, $obj_id): void
213  {
214  $processLocker = $this->processLockerFactory->withContextId((int) $active_id)->getLocker();
215 
216  $testSession = new ilTestSession();
217  $testSession->loadFromDb($active_id);
218 
219  if(ilObject::_exists($obj_id)) {
220  $test = new ilObjTest($obj_id, false);
221 
222  assQuestion::_updateTestPassResults(
223  $active_id,
224  $testSession->getPass(),
225  $test->areObligationsEnabled(),
226  null,
227  $obj_id
228  );
229 
230  $pass_finisher = new ilTestPassFinishTasks($active_id, $obj_id);
231  $pass_finisher->performFinishTasks($processLocker);
232 
233  $this->log->info('Test session with active id (' . $active_id . ') and obj_id (' . $obj_id . ') is now finished.');
234  } else {
235  $this->log->info('Test object with id (' . $obj_id . ') does not exist.');
236  }
237  }
238 }
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getLogger(string $a_component_id)
Get component logger.
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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
global $DIC
Definition: feed.php:28
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
string $key
Consumer key/client ID value.
Definition: System.php:193
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$query