ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.ilTestPassesSelector.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
28 {
29  private ?int $active_id = null;
30  private ?int $last_finished_pass = null;
31  private ?array $passes = null;
32  private array $test_passed_once_cache = [];
33 
34  public function __construct(
35  private ilDBInterface $db,
36  private ilObjTest $test_obj
37  ) {
38  }
39 
40  public function getActiveId(): ?int
41  {
42  return $this->active_id;
43  }
44 
45  public function setActiveId(?int $active_id): void
46  {
47  $this->active_id = $active_id;
48  }
49 
50  public function getLastFinishedPass(): ?int
51  {
53  }
54 
55  public function setLastFinishedPass(?int $last_finished_pass): void
56  {
57  $this->last_finished_pass = $last_finished_pass === null ? -1 : $last_finished_pass;
58  }
59 
60  private function passesLoaded(): bool
61  {
62  return is_array($this->passes);
63  }
64 
65  private function ensureLoadedPasses()
66  {
67  if (!$this->passesLoaded()) {
68  $this->loadPasses();
69  }
70  }
71  private function loadPasses(): void
72  {
73  $query = '
74  SELECT DISTINCT tst_pass_result.* FROM tst_pass_result
75  LEFT JOIN tst_test_result
76  ON tst_pass_result.pass = tst_test_result.pass
77  AND tst_pass_result.active_fi = tst_test_result.active_fi
78  WHERE tst_pass_result.active_fi = %s
79  ORDER BY tst_pass_result.pass
80  ';
81 
82  $res = $this->db->queryF(
83  $query,
84  ['integer'],
85  [$this->getActiveId()]
86  );
87 
88  $this->passes = [];
89 
90  while ($row = $this->db->fetchAssoc($res)) {
91  $this->passes[$row['pass']] = $row;
92  }
93  }
94 
95  private function getLazyLoadedPasses(): array
96  {
97  $this->ensureLoadedPasses();
98  return $this->passes;
99  }
100 
101  public function loadLastFinishedPass(): void
102  {
103  $query = 'SELECT last_finished_pass FROM tst_active WHERE active_id = %s';
104 
105  $res = $this->db->queryF(
106  $query,
107  ['integer'],
108  [$this->getActiveId()]
109  );
110 
111  while ($row = $this->db->fetchAssoc($res)) {
112  $this->setLastFinishedPass($row['last_finished_pass']);
113  }
114  }
115 
116  public function getExistingPasses(): array
117  {
118  return array_keys($this->getLazyLoadedPasses());
119  }
120 
121  public function hasExistingPasses(): bool
122  {
123  return $this->getExistingPasses() !== [];
124  }
125 
126  public function getNumExistingPasses(): int
127  {
128  return count($this->getExistingPasses());
129  }
130 
131  public function openPassExists(): bool
132  {
133  return count($this->getExistingPasses()) > count($this->getClosedPasses());
134  }
135 
136  public function getClosedPasses(): array
137  {
138  $existing_passes = $this->getExistingPasses();
139  return $this->fetchClosedPasses($existing_passes);
140  }
141 
142  public function getReportablePasses(): array
143  {
144  $existing_passes = $this->getExistingPasses();
145  return $this->fetchReportablePasses($existing_passes);
146  }
147 
148  public function hasReportablePasses(): bool
149  {
150  return (bool) count($this->getReportablePasses());
151  }
152 
153  private function fetchReportablePasses(array $existing_passes): array
154  {
155  $last_pass = $this->fetchLastPass($existing_passes);
156 
157  $reportable_passes = [];
158 
159  foreach ($existing_passes as $pass) {
160  if ($this->isReportablePass($last_pass, $pass)) {
161  $reportable_passes[] = $pass;
162  }
163  }
164 
165  return $reportable_passes;
166  }
167 
168  private function fetchClosedPasses(array $existing_passes): array
169  {
170  $closed_passes = [];
171 
172  foreach ($existing_passes as $pass) {
173  if ($this->isClosedPass($pass)) {
174  $closed_passes[] = $pass;
175  }
176  }
177 
178  return $closed_passes;
179  }
180 
181  private function fetchLastPass(array $existing_passes): ?int
182  {
183  $last_pass = null;
184 
185  foreach ($existing_passes as $pass) {
186  if ($last_pass === null || $pass > $last_pass) {
187  $last_pass = $pass;
188  }
189  }
190 
191  return $last_pass;
192  }
193 
194  private function isReportablePass(int $last_pass, int $pass): bool
195  {
196  switch ($this->test_obj->getScoreReporting()) {
198  return true;
199 
201  return $this->isReportingDateReached();
202 
204  if ($pass < $last_pass) {
205  return true;
206  }
207 
208  return $this->isClosedPass($pass);
209 
211  if (!$this->hasTestPassedOnce($this->getActiveId())) {
212  return false;
213  }
214 
215  return $this->isClosedPass($pass);
216  }
217 
218  return false;
219  }
220 
222  {
223  if ($this->getLastFinishedPass() === null) {
224  throw new ilTestException('invalid object state: last finished pass was not set!');
225  }
226  }
227 
228  private function isClosedPass(int $pass): bool
229  {
231 
232  if ($pass <= $this->getLastFinishedPass()) {
233  return true;
234  }
235 
236  if ($this->isProcessingTimeReached($pass)) {
237  return true;
238  }
239 
240  return false;
241  }
242 
243  private function isReportingDateReached(): bool
244  {
245  $reporting_date = $this->test_obj->getScoreSettings()->getResultSummarySettings()->getReportingDate();
246  return $reporting_date <= new DateTimeImmutable('now', new DateTimeZone('UTC'));
247  }
248 
249  private function isProcessingTimeReached(int $pass): bool
250  {
251  if (!$this->test_obj->getEnableProcessingTime()) {
252  return false;
253  }
254 
255  $startingTime = $this->test_obj->getStartingTimeOfUser($this->getActiveId(), $pass);
256 
257  if ($startingTime === false) {
258  return false;
259  }
260 
261  return $this->test_obj->isMaxProcessingTimeReached($startingTime, $this->getActiveId());
262  }
263 
264  public function getLastFinishedPassTimestamp(): ?int
265  {
266  $last_finished_pass = $this->getLastFinishedPass();
267  if ($last_finished_pass === null || $last_finished_pass === -1) {
268  return null;
269  }
270 
271  $passes = $this->getLazyLoadedPasses();
272  if (!isset($passes[$last_finished_pass])) {
273  return null;
274  }
275  return $passes[$last_finished_pass]['tstamp'];
276  }
277 
278  public function hasTestPassedOnce(int $active_id): bool
279  {
280  if (!isset($this->test_passed_once_cache[$active_id])) {
281  $this->test_passed_once_cache[$active_id] = false;
282 
283  $res = $this->db->queryF(
284  'SELECT passed_once FROM tst_result_cache WHERE active_fi = %s',
285  ['integer'],
286  [$active_id]
287  );
288 
289  while ($row = $this->db->fetchAssoc($res)) {
290  $this->test_passed_once_cache[$active_id] = (bool) $row['passed_once'];
291  }
292  }
293 
294  return $this->test_passed_once_cache[$active_id];
295  }
296 }
$res
Definition: ltiservices.php:69
fetchClosedPasses(array $existing_passes)
__construct(private ilDBInterface $db, private ilObjTest $test_obj)
Base Exception for all Exceptions relating to Modules/Test.
fetchLastPass(array $existing_passes)
setLastFinishedPass(?int $last_finished_pass)
fetchReportablePasses(array $existing_passes)
isReportablePass(int $last_pass, int $pass)