ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.QuestionInfoService.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 namespace ILIAS\TestQuestionPool;
6 
8 {
9  public function __construct(
10  private \ilDBInterface $database,
11  private \ilComponentFactory $component_factory,
12  private \ilLanguage $lng
13  ) {
14  }
15 
16  public function getQuestionTitle(int $question_id): string
17  {
18  if ($question_id < 1) {
19  return "";
20  }
21 
22  $result = $this->database->queryF(
23  "SELECT title FROM qpl_questions WHERE qpl_questions.question_id = %s",
24  ['integer'],
25  [$question_id]
26  );
27  if ($result->numRows() === 1) {
28  $data = $this->database->fetchAssoc($result);
29  return $data["title"];
30  }
31  return "";
32  }
33 
34  public function getQuestionType(int $question_id): string
35  {
36  if ($question_id < 1) {
37  return "";
38  }
39 
40  $result = $this->database->queryF(
41  "SELECT type_tag FROM qpl_questions, qpl_qst_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
42  ['integer'],
43  [$question_id]
44  );
45 
46  if ($result->numRows() === 1) {
47  $data = $this->database->fetchAssoc($result);
48  return $data["type_tag"];
49  }
50 
51  return "";
52  }
53 
54  public function getQuestionTypeName(int $question_id): string
55  {
56  $question_type = $this->getQuestionType($question_id);
57 
58  if ($question_type === '') {
59  return '';
60  }
61 
62  if (file_exists("./Modules/TestQuestionPool/classes/class." . $question_type . ".php")) {
63  return $this->lng->txt($question_type);
64  }
65 
66  foreach ($this->component_factory->getActivePluginsInSlot('qst') as $pl) {
67  if ($pl->getQuestionType() === $question_type) {
68  return $pl->getQuestionTypeTranslation();
69  }
70  }
71  return "";
72  }
73 
74  public function getQuestionText(int $a_q_id): string
75  {
76  $result = $this->database->queryF(
77  "SELECT question_text FROM qpl_questions WHERE question_id = %s",
78  ['integer'],
79  [$a_q_id]
80  );
81 
82  if ($result->numRows() === 1) {
83  $row = $this->database->fetchAssoc($result);
84  return $row["question_text"];
85  }
86 
87  return "";
88  }
89 
90  public function getFractionOfReachedToReachablePointsTotal(int $a_q_id): float
91  {
92  $result = $this->database->queryF(
93  "SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
94  ['integer','integer'],
95  [$a_q_id, $a_q_id]
96  );
97  if ($result->numRows() === 0) {
98  return 0.0;
99  }
100 
101  $found_id = [];
102  while ($row = $this->database->fetchAssoc($result)) {
103  $found_id[] = $row["question_id"];
104  }
105 
106  $result = $this->database->query("SELECT question_fi, points FROM tst_test_result WHERE " . $this->database->in('question_fi', $found_id, false, 'integer'));
107  $answers = [];
108  while ($row = $this->database->fetchAssoc($result)) {
109  $reached = $row["points"];
110  $max = $this->getMaximumPoints($row["question_fi"]);
111  $answers[] = ["reached" => $reached, "max" => $max];
112  }
113 
114  $max = 0.0;
115  $reached = 0.0;
116  foreach ($answers as $key => $value) {
117  $max += $value["max"];
118  $reached += $value["reached"];
119  }
120  if ($max > 0) {
121  return $reached / $max;
122  }
123  return 0;
124  }
125 
126  public function getMaximumPoints(int $question_id): float
127  {
128  $points = 0.0;
129  $result = $this->database->queryF(
130  "SELECT points FROM qpl_questions WHERE question_id = %s",
131  ['integer'],
132  [$question_id]
133  );
134  if ($this->database->numRows($result) === 1) {
135  $row = $this->database->fetchAssoc($result);
136  $points = (float) $row["points"];
137  }
138  return $points;
139  }
140 
141  public function getQuestionInfo(int $question_id): array
142  {
143  $result = $this->database->queryF(
144  "SELECT qpl_questions.*, qpl_qst_type.type_tag FROM qpl_qst_type, qpl_questions WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
145  ['integer'],
146  [$question_id]
147  );
148 
149  if ($this->database->numRows($result)) {
150  return $this->database->fetchAssoc($result);
151  }
152  return [];
153  }
154 
161  public function areQuestionsAnsweredByUser(int $a_user_id, array $a_question_ids): bool
162  {
163  $res = $this->database->queryF(
164  "SELECT DISTINCT(question_fi) FROM tst_test_result JOIN tst_active " .
165  "ON (active_id = active_fi) " .
166  "WHERE " . $this->database->in('question_fi', $a_question_ids, false, 'integer') .
167  " AND user_fi = %s",
168  ['integer'],
169  [$a_user_id]
170  );
171  return $res->numRows() === count($a_question_ids);
172  }
173 
174  public function lookupResultRecordExist(int $activeId, int $questionId, int $pass): bool
175  {
176  $query = "
177  SELECT COUNT(*) cnt
178  FROM tst_test_result
179  WHERE active_fi = %s
180  AND question_fi = %s
181  AND pass = %s
182  ";
183 
184  $row = $this->database->fetchAssoc($this->database->queryF($query, ['integer', 'integer', 'integer'], [$activeId, $questionId, $pass]));
185 
186  return $row['cnt'] > 0;
187  }
188 
192  public function isClone(int $question_id): bool
193  {
194  $result = $this->database->queryF(
195  "SELECT COUNT(original_id) cnt FROM qpl_questions WHERE question_id = %s",
196  ['integer'],
197  [$question_id]
198  );
199  $row = $this->database->fetchAssoc($result);
200  return ((int) $row["cnt"]) > 0;
201  }
202 
206  public function isInUse(int $question_id = 0): bool
207  {
208  return $this->usageNumber($question_id) > 0;
209  }
210 
214  public function usageNumber(int $question_id = 0): int
215  {
216  $result = $this->database->queryF(
217  "SELECT COUNT(qpl_questions.question_id) question_count FROM qpl_questions, tst_test_question WHERE qpl_questions.original_id = %s AND qpl_questions.question_id = tst_test_question.question_fi",
218  ['integer'],
219  [$question_id]
220  );
221  $row = $this->database->fetchAssoc($result);
222  $count = (int) $row["question_count"];
223 
224  $result = $this->database->queryF(
225  "
226  SELECT tst_active.test_fi
227  FROM qpl_questions
228  INNER JOIN tst_test_rnd_qst ON tst_test_rnd_qst.question_fi = qpl_questions.question_id
229  INNER JOIN tst_active ON tst_active.active_id = tst_test_rnd_qst.active_fi
230  WHERE qpl_questions.original_id = %s
231  GROUP BY tst_active.test_fi",
232  ['integer'],
233  [$question_id]
234  );
235  $count += $this->database->numRows($result);
236 
237  return $count;
238  }
239 
240  public function questionExists(int $question_id): bool
241  {
242  if ($question_id < 1) {
243  return false;
244  }
245 
246  $result = $this->database->queryF(
247  "SELECT question_id FROM qpl_questions WHERE question_id = %s",
248  ['integer'],
249  [$question_id]
250  );
251  return $result->numRows() === 1;
252  }
253 
254  public function questionExistsInPool(int $question_id): bool
255  {
256  if ($question_id < 1) {
257  return false;
258  }
259 
260  $result = $this->database->queryF(
261  "SELECT question_id FROM qpl_questions INNER JOIN object_data ON obj_fi = obj_id WHERE question_id = %s AND type = 'qpl'",
262  ['integer'],
263  [$question_id]
264  );
265  return $this->database->numRows($result) === 1;
266  }
267 
268  public function isUsedInRandomTest(int $question_id): bool
269  {
270  $result = $this->database->queryF(
271  "SELECT test_random_question_id FROM tst_test_rnd_qst WHERE question_fi = %s",
272  ['integer'],
273  [$question_id]
274  );
275  return $this->database->numRows($result) > 0;
276  }
277 
278  public function originalQuestionExists(int $questionId): bool
279  {
280  $query = "
281  SELECT COUNT(dupl.question_id) cnt
282  FROM qpl_questions dupl
283  INNER JOIN qpl_questions orig
284  ON orig.question_id = dupl.original_id
285  WHERE dupl.question_id = %s
286  ";
287 
288  $res = $this->database->queryF($query, ['integer'], [$questionId]);
289  $row = $this->database->fetchAssoc($res);
290 
291  return $row['cnt'] > 0;
292  }
293 
294  public function getOriginalId(int $question_id): int
295  {
296  $result = $this->database->queryF(
297  "SELECT * FROM qpl_questions WHERE question_id = %s",
298  ['integer'],
299  [$question_id]
300  );
301  if ($this->database->numRows($result) > 0) {
302  $row = $this->database->fetchAssoc($result);
303  if ($row["original_id"] > 0) {
304  return $row["original_id"];
305  }
306 
307  return (int) $row["question_id"];
308  }
309 
310  return -1;
311  }
312 
313  public function getQuestionsMissingResultRecord(int $activeId, int $pass, array $questionIds): array
314  {
315  $IN_questionIds = $this->database->in('question_fi', $questionIds, false, 'integer');
316 
317  $query = "
318  SELECT question_fi
319  FROM tst_test_result
320  WHERE active_fi = %s
321  AND pass = %s
322  AND $IN_questionIds
323  ";
324 
325  $res = $this->database->queryF(
326  $query,
327  ['integer', 'integer'],
328  [$activeId, $pass]
329  );
330 
331  $questionsHavingResultRecord = [];
332 
333  while ($row = $this->database->fetchAssoc($res)) {
334  $questionsHavingResultRecord[] = $row['question_fi'];
335  }
336 
337  $questionsMissingResultRecordt = array_diff(
338  $questionIds,
339  $questionsHavingResultRecord
340  );
341 
342  return $questionsMissingResultRecordt;
343  }
344 
345  public function missingResultRecordExists(int $activeId, int $pass, array $questionIds): bool
346  {
347  $IN_questionIds = $this->database->in('question_fi', $questionIds, false, 'integer');
348 
349  $query = "
350  SELECT COUNT(*) cnt
351  FROM tst_test_result
352  WHERE active_fi = %s
353  AND pass = %s
354  AND $IN_questionIds
355  ";
356 
357  $row = $this->database->fetchAssoc($this->database->queryF(
358  $query,
359  ['integer', 'integer'],
360  [$activeId, $pass]
361  ));
362 
363  return $row['cnt'] < count($questionIds);
364  }
365 
366  public function isInActiveTest(int $obj_id): bool
367  {
368  $query = 'SELECT user_fi FROM tst_active ' . PHP_EOL
369  . 'JOIN tst_test_question ON tst_test_question.test_fi = tst_active.test_fi ' . PHP_EOL
370  . 'JOIN qpl_questions ON qpl_questions.question_id = tst_test_question.question_fi ' . PHP_EOL
371  . 'WHERE qpl_questions.obj_fi = ' . $this->database->quote($obj_id, 'integer');
372 
373  $res = $this->database->query($query);
374  return $res->numRows() > 0;
375  }
376 
377  public function questionTitleExistsInPool(int $questionpool_id, string $title): bool
378  {
379  $result = $this->database->queryF(
380  "SELECT * FROM qpl_questions WHERE obj_fi = %s AND title = %s",
381  ['integer','text'],
382  [$questionpool_id, $title]
383  );
384  return $result->numRows() > 0;
385  }
386 }
$res
Definition: ltiservices.php:69
questionTitleExistsInPool(int $questionpool_id, string $title)
isInUse(int $question_id=0)
Checks whether the question is in use or not in pools or tests.
__construct(private \ilDBInterface $database, private \ilComponentFactory $component_factory, private \ilLanguage $lng)
getQuestionsMissingResultRecord(int $activeId, int $pass, array $questionIds)
$lng
lookupResultRecordExist(int $activeId, int $questionId, int $pass)
string $key
Consumer key/client ID value.
Definition: System.php:193
missingResultRecordExists(int $activeId, int $pass, array $questionIds)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
usageNumber(int $question_id=0)
Returns the number of place the question is in use in pools or tests.
areQuestionsAnsweredByUser(int $a_user_id, array $a_question_ids)
Checks if an array of question ids is answered by a user or not.
isClone(int $question_id)
Checks whether the question is a clone of another question or not.