ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilCronFinishUnfinishedTestPasses.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
28 {
32  protected $log;
33 
34  protected ilLanguage $lng;
35  protected ilDBInterface $db;
36  protected ilObjUser $user;
38  protected int $now;
39  protected array $unfinished_passes;
40  protected array $test_ids;
41  protected array $test_ending_times;
43 
44  public function __construct()
45  {
47  global $DIC;
48 
49  $this->log = ilLoggerFactory::getLogger('tst');
50  $this->lng = $DIC['lng'];
51  $this->user = $DIC['ilUser'];
52  $this->lng->loadLanguageModule('assessment');
53  $this->db = $DIC->database();
54  $this->obj_data_cache = $DIC['ilObjDataCache'];
55  $this->now = time();
56  $this->unfinished_passes = [];
57  $this->test_ids = [];
58  $this->test_ending_times = [];
59 
60  $this->processLockerFactory = new ilTestProcessLockerFactory(
61  new ilSetting('assessment'),
62  $this->db
63  );
64  }
65 
66  public function getId(): string
67  {
68  return 'finish_unfinished_passes';
69  }
70 
71  public function getTitle(): string
72  {
73  return $this->lng->txt('finish_unfinished_passes');
74  }
75 
76  public function getDescription(): string
77  {
78  return $this->lng->txt('finish_unfinished_passes_desc');
79  }
80 
82  {
83  return CronJobScheduleType::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 = '
131  SELECT tst_active.active_id,
132  tst_active.tries,
133  tst_active.user_fi usr_id,
134  tst_active.test_fi test_fi,
135  usr_data.login,
136  usr_data.lastname,
137  usr_data.firstname,
138  tst_active.submitted test_finished,
139  usr_data.matriculation,
140  usr_data.active,
141  tst_active.lastindex,
142  tst_active.last_started_pass last_started
143  FROM tst_active
144  LEFT JOIN usr_data
145  ON tst_active.user_fi = usr_data.usr_id
146  WHERE IFNULL(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass
147  ';
148  $result = $this->db->query($query);
149  while ($row = $this->db->fetchAssoc($result)) {
150  $this->unfinished_passes[] = $row;
151  $this->test_ids[] = $row['test_fi'];
152  }
153  }
154 
155  protected function getTestsFinishAndProcessingTime(): void
156  {
157  $query = 'SELECT test_id, obj_fi, ending_time, ending_time_enabled, processing_time, enable_processing_time FROM tst_tests WHERE ' .
158  $this->db->in('test_id', $this->test_ids, false, 'integer');
159  $result = $this->db->query($query);
160  while ($row = $this->db->fetchAssoc($result)) {
161  $this->test_ending_times[$row['test_id']] = $row;
162  }
163  $this->log->info('Gathered data for ' . count($this->test_ids) . ' test id(s) => (' . implode(',', $this->test_ids) . ')');
164  }
165 
166  protected function processPasses(): void
167  {
168  $now = time();
169  foreach ($this->unfinished_passes as $key => $data) {
170  $test_id = $data['test_fi'];
171  $can_not_be_finished = true;
172  if (array_key_exists($test_id, $this->test_ending_times)) {
173  if ($this->test_ending_times[$test_id]['ending_time_enabled'] == 1) {
174  $this->log->info('Test (' . $test_id . ') has ending time (' . $this->test_ending_times[$test_id]['ending_time'] . ')');
175  $ending_time = $this->test_ending_times[$test_id]['ending_time'];
176  if ($ending_time < $now) {
177  $this->finishPassForUser($data['active_id'], $this->test_ending_times[$test_id]['obj_fi']);
178  $can_not_be_finished = false;
179  } else {
180  $this->log->info('Test (' . $test_id . ') ending time (' . $this->test_ending_times[$test_id]['ending_time'] . ') > now (' . $now . ') is not reached.');
181  }
182  } else {
183  $this->log->info('Test (' . $test_id . ') has no ending time.');
184  }
185  if ($this->test_ending_times[$test_id]['enable_processing_time'] == 1) {
186  $this->log->info('Test (' . $test_id . ') has processing time (' . $this->test_ending_times[$test_id]['processing_time'] . ')');
187  $obj_id = $this->test_ending_times[$test_id]['obj_fi'];
188  if (ilObject::_exists($obj_id)) {
189  $test_obj = new ilObjTest($obj_id, false);
190  $startingTime = $test_obj->getStartingTimeOfUser($data['active_id']);
191  $max_processing_time = $test_obj->isMaxProcessingTimeReached($startingTime, $data['active_id']);
192  if ($max_processing_time) {
193  $this->log->info('Max Processing time reached for user id (' . $data['usr_id'] . ') so test with active id (' . $data['active_id'] . ') will be finished.');
194  $this->finishPassForUser($data['active_id'], $this->test_ending_times[$test_id]['obj_fi']);
195  $can_not_be_finished = false;
196  } else {
197  $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');
198  }
199  } else {
200  $this->log->info('Test object with id (' . $obj_id . ') does not exist.');
201  }
202  } else {
203  $this->log->info('Test (' . $test_id . ') has no processing time.');
204  }
205 
206  if ($can_not_be_finished) {
207  $this->log->info('Test session with active id (' . $data['active_id'] . ') can not be finished by this cron job.');
208  }
209  }
210  }
211  }
212 
213  protected function finishPassForUser($active_id, $obj_id): void
214  {
215  $processLocker = $this->processLockerFactory->withContextId((int) $active_id)->getLocker();
216 
217  $test_session = new ilTestSession($this->db, $this->user);
218  $test_session->loadFromDb($active_id);
219 
220  if (ilObject::_exists($obj_id)) {
221  $test = new ilObjTest($obj_id, false);
222 
223  $test->updateTestPassResults(
224  $active_id,
225  $test_session->getPass(),
226  $test->areObligationsEnabled(),
227  null,
228  $obj_id
229  );
230 
231  (new ilTestPassFinishTasks($test_session, $test))->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 }
Class ilTestPassFinishTasks.
static getLogger(string $a_component_id)
Get component logger.
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
__construct(VocabulariesInterface $vocabularies)
string $key
Consumer key/client ID value.
Definition: System.php:193
Class ilCronFinishUnfinishedTestPasses.