ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilCronFinishUnfinishedTestPasses.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
23 use ILIAS\Test\Results\Data\Repository as TestResultRepository;
26 
32 {
33  protected readonly TestLogger $logger;
34 
35  protected readonly ilLanguage $lng;
36  protected readonly ilDBInterface $db;
37  protected readonly ilObjUser $user;
38  protected readonly ilObjectDataCache $obj_data_cache;
39  protected int $now;
40  protected array $unfinished_passes;
41  protected array $test_ids;
42  protected array $test_ending_times;
44  protected TestResultRepository $test_pass_result_repository;
45 
46  public function __construct()
47  {
49  global $DIC;
50 
51  $this->logger = TestDIC::dic()['logging.logger'];
52  $this->lng = $DIC['lng'];
53  $this->user = $DIC['ilUser'];
54  $this->lng->loadLanguageModule('assessment');
55  $this->db = $DIC->database();
56  $this->obj_data_cache = $DIC['ilObjDataCache'];
57  $this->now = time();
58  $this->unfinished_passes = [];
59  $this->test_ids = [];
60  $this->test_ending_times = [];
61 
62  $this->processLockerFactory = new ilTestProcessLockerFactory(
63  new ilSetting('assessment'),
64  $this->db
65  );
66 
67  $this->test_pass_result_repository = TestDic::dic()['results.data.test_result_repository'];
68  }
69 
70  public function getId(): string
71  {
72  return 'finish_unfinished_passes';
73  }
74 
75  public function getTitle(): string
76  {
77  return $this->lng->txt('finish_unfinished_passes');
78  }
79 
80  public function getDescription(): string
81  {
82  return $this->lng->txt('finish_unfinished_passes_desc');
83  }
84 
86  {
87  return CronJobScheduleType::SCHEDULE_TYPE_DAILY;
88  }
89 
90  public function getDefaultScheduleValue(): int
91  {
92  return 1;
93  }
94 
95  public function hasAutoActivation(): bool
96  {
97  return false;
98  }
99 
100  public function hasFlexibleSchedule(): bool
101  {
102  return true;
103  }
104 
105  public function hasCustomSettings(): bool
106  {
107  return true;
108  }
109 
110  public function run(): ilCronJobResult
111  {
112  $this->logger->info('start inf cronjob...');
113 
114  $result = new ilCronJobResult();
115 
117  if (count($this->unfinished_passes) > 0) {
118  $this->logger->info('found ' . count($this->unfinished_passes) . ' unfinished passes starting analyses.');
120  $this->processPasses();
121  } else {
122  $this->logger->info('No unfinished passes found.');
123  }
124 
125  $result->setStatus(ilCronJobResult::STATUS_OK);
126 
127  $this->logger->info(' ...finishing cronjob.');
128 
129  return $result;
130  }
131 
132  protected function gatherUsersWithUnfinishedPasses(): void
133  {
134  $query = '
135  SELECT tst_active.active_id,
136  tst_active.tries,
137  tst_active.user_fi usr_id,
138  tst_active.test_fi test_fi,
139  usr_data.login,
140  usr_data.lastname,
141  usr_data.firstname,
142  tst_active.submitted test_finished,
143  usr_data.matriculation,
144  usr_data.active,
145  tst_active.lastindex,
146  tst_active.last_started_pass last_started
147  FROM tst_active
148  LEFT JOIN usr_data
149  ON tst_active.user_fi = usr_data.usr_id
150  WHERE IFNULL(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass
151  ';
152  $result = $this->db->query($query);
153  while ($row = $this->db->fetchAssoc($result)) {
154  $this->unfinished_passes[] = $row;
155  $this->test_ids[] = $row['test_fi'];
156  }
157  }
158 
159  protected function getTestsFinishAndProcessingTime(): void
160  {
161  $query = 'SELECT test_id, obj_fi, ending_time, ending_time_enabled, processing_time, enable_processing_time FROM tst_tests WHERE ' .
162  $this->db->in('test_id', $this->test_ids, false, 'integer');
163  $result = $this->db->query($query);
164  while ($row = $this->db->fetchAssoc($result)) {
165  $this->test_ending_times[$row['test_id']] = $row;
166  }
167  $this->logger->info('Gathered data for ' . count($this->test_ids) . ' test id(s) => (' . implode(',', $this->test_ids) . ')');
168  }
169 
170  protected function processPasses(): void
171  {
172  foreach ($this->unfinished_passes as $data) {
173  $test_id = $data['test_fi'];
174  if (!array_key_exists($test_id, $this->test_ending_times)) {
175  continue;
176  }
177  if (!$this->finishPassOnEndingTime($test_id, $data['active_id'])
178  && !$this->finishPassOnProcessingTime(
179  $test_id,
180  $data['usr_id'],
181  $data['active_id']
182  )
183  ) {
184  $this->logger->info('Test session with active id ('
185  . $data['active_id'] . ') can not be finished by this cron job.');
186  }
187  }
188 
189  }
190 
191  private function finishPassOnEndingTime(int $test_id, int $active_id): bool
192  {
193  $now = time();
194  if ($this->test_ending_times[$test_id]['ending_time_enabled'] !== 1) {
195  $this->logger->info('Test (' . $test_id . ') has no ending time.');
196  return false;
197  }
198 
199  $this->logger->info('Test (' . $test_id . ') has ending time ('
200  . $this->test_ending_times[$test_id]['ending_time'] . ')');
201  $ending_time = $this->test_ending_times[$test_id]['ending_time'];
202  if ($ending_time >= $now) {
203  $this->logger->info('Test (' . $test_id . ') ending time ('
204  . $this->test_ending_times[$test_id]['ending_time']
205  . ') > now (' . $now . ') is not reached.');
206  return false;
207  }
208 
209  $this->finishPassForUser($active_id, $this->test_ending_times[$test_id]['obj_fi']);
210  return true;
211  }
212 
213  private function finishPassOnProcessingTime(
214  int $test_id,
215  int $usr_id,
216  int $active_id
217  ): bool {
218  if ($this->test_ending_times[$test_id]['enable_processing_time'] !== 1) {
219  $this->logger->info('Test (' . $test_id . ') has no processing time.');
220  return false;
221  }
222 
223  $this->logger->info('Test (' . $test_id . ') has processing time (' . $this->test_ending_times[$test_id]['processing_time'] . ')');
224  $obj_id = $this->test_ending_times[$test_id]['obj_fi'];
225 
226  if (!ilObject::_exists($obj_id)) {
227  $this->logger->info('Test object with id (' . $obj_id . ') does not exist.');
228  return false;
229  }
230 
231  $test_obj = new ilObjTest($obj_id, false);
232  $startingTime = $test_obj->getStartingTimeOfUser($active_id);
233  $max_processing_time = $test_obj->isMaxProcessingTimeReached($startingTime, $active_id);
234  if (!$max_processing_time) {
235  $this->logger->info('Max Processing time not reached for user id ('
236  . $usr_id . ') in test with active id ('
237  . $active_id . '). Starting time: ' . $startingTime
238  . ' Processing time: ' . $test_obj->getProcessingTime() . ' / '
239  . $test_obj->getProcessingTimeInSeconds() . 's');
240  return false;
241  }
242 
243  $this->logger->info('Max Processing time reached for user id ('
244  . $usr_id . ') so test with active id ('
245  . $active_id . ') will be finished.');
246  $this->finishPassForUser($active_id, $this->test_ending_times[$test_id]['obj_fi']);
247  return true;
248  }
249 
250  protected function finishPassForUser($active_id, $obj_id): void
251  {
252  $processLocker = $this->processLockerFactory->withContextId((int) $active_id)->getLocker();
253 
254  $test_session = new ilTestSession($this->db, $this->user);
255  $test_session->loadFromDb($active_id);
256 
257  if (ilObject::_exists($obj_id)) {
258  $test = new ilObjTest($obj_id, false);
259 
260  $test->updateTestPassResults(
261  $active_id,
262  $test_session->getPass(),
263  null,
264  $obj_id
265  );
266 
268  $test_session,
269  $test,
270  $this->test_pass_result_repository
271  ))->performFinishTasks($processLocker, StatusOfAttempt::FINISHED_BY_CRONJOB);
272  $this->logger->info('Test session with active id (' . $active_id . ') and obj_id (' . $obj_id . ') is now finished.');
273  } else {
274  $this->logger->info('Test object with id (' . $obj_id . ') does not exist.');
275  }
276  }
277 }
Class ilTestPassFinishTasks.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
global $DIC
Definition: shib_login.php:25
Class ilCronFinishUnfinishedTestPasses.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct(Container $dic, ilPlugin $plugin)
finishPassOnProcessingTime(int $test_id, int $usr_id, int $active_id)