ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilTestRandomQuestionSetConfig.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
30 {
31  public const QUESTION_AMOUNT_CONFIG_MODE_PER_TEST = 'TEST';
32  public const QUESTION_AMOUNT_CONFIG_MODE_PER_POOL = 'POOL';
33 
35  private ?string $questionAmountConfigurationMode = null;
36  private ?int $questionAmountPerTest = null;
37  private ?int $lastQuestionSyncTimestamp = null;
38  private array $buildableMessages = [];
39 
40  public function setPoolsWithHomogeneousScoredQuestionsRequired(bool $requirePoolsWithHomogeneousScoredQuestions): void
41  {
42  $this->requirePoolsWithHomogeneousScoredQuestions = $requirePoolsWithHomogeneousScoredQuestions;
43  }
44 
46  {
48  }
49 
50  public function setQuestionAmountConfigurationMode(?string $questionAmountConfigurationMode): void
51  {
52  $this->questionAmountConfigurationMode = $questionAmountConfigurationMode;
53  }
54 
55  public function getQuestionAmountConfigurationMode(): ?string
56  {
58  }
59 
61  {
62  return $this->getQuestionAmountConfigurationMode() == self::QUESTION_AMOUNT_CONFIG_MODE_PER_POOL;
63  }
64 
66  {
67  return $this->getQuestionAmountConfigurationMode() == self::QUESTION_AMOUNT_CONFIG_MODE_PER_TEST;
68  }
69 
70  public function isValidQuestionAmountConfigurationMode(string $amountMode): bool
71  {
72  switch ($amountMode) {
73  case self::QUESTION_AMOUNT_CONFIG_MODE_PER_POOL:
74  case self::QUESTION_AMOUNT_CONFIG_MODE_PER_TEST:
75 
76  return true;
77  }
78 
79  return false;
80  }
81 
82  public function setQuestionAmountPerTest(?int $questionAmountPerTest): void
83  {
84  $this->questionAmountPerTest = $questionAmountPerTest;
85  }
86 
87  public function getQuestionAmountPerTest(): ?int
88  {
90  }
91 
92  public function setLastQuestionSyncTimestamp(int $lastQuestionSyncTimestamp): void
93  {
94  $this->lastQuestionSyncTimestamp = $lastQuestionSyncTimestamp;
95  }
96 
97  public function getLastQuestionSyncTimestamp(): ?int
98  {
100  }
101 
102  public function getBuildableMessages(): array
103  {
105  }
106 
107  public function initFromArray(array $data_array): void
108  {
109  foreach ($data_array as $field => $value) {
110  switch ($field) {
111  case 'req_pools_homo_scored': $this->setPoolsWithHomogeneousScoredQuestionsRequired((bool) $value);
112  break;
113  case 'quest_amount_cfg_mode': $this->setQuestionAmountConfigurationMode($value);
114  break;
115  case 'quest_amount_per_test': $this->setQuestionAmountPerTest($value);
116  break;
117  case 'quest_sync_timestamp': $this->setLastQuestionSyncTimestamp($value);
118  break;
119  }
120  }
121  }
122 
123  public function loadFromDb(): void
124  {
125  $res = $this->db->queryF(
126  "SELECT * FROM tst_rnd_quest_set_cfg WHERE test_fi = %s",
127  ['integer'],
128  [$this->test_obj->getTestId()]
129  );
130 
131  $row = $this->db->fetchAssoc($res);
132  if ($row !== null) {
133  $this->initFromArray($row);
134  }
135  }
136 
137  public function saveToDb(): void
138  {
139  if ($this->dbRecordExists($this->test_obj->getTestId())) {
140  $this->updateDbRecord($this->test_obj->getTestId());
141  return;
142  }
143 
144  $this->insertDbRecord($this->test_obj->getTestId());
145  }
146 
147  public function cloneToDbForTestId(int $test_id): void
148  {
149  $this->insertDbRecord($test_id);
150  }
151 
152  public function deleteFromDb(): void
153  {
154  $this->db->manipulateF(
155  "DELETE FROM tst_rnd_quest_set_cfg WHERE test_fi = %s",
156  ['integer'],
157  [$this->test_obj->getTestId()]
158  );
159  }
160 
161  private function dbRecordExists(int $test_id): bool
162  {
163  $res = $this->db->queryF(
164  "SELECT COUNT(*) cnt FROM tst_rnd_quest_set_cfg WHERE test_fi = %s",
165  ['integer'],
166  [$test_id]
167  );
168 
169  $row = $this->db->fetchAssoc($res);
170 
171  return (bool) $row['cnt'];
172  }
173 
174  private function updateDbRecord(int $test_id): void
175  {
176  $this->db->update(
177  'tst_rnd_quest_set_cfg',
178  [
179  'req_pools_homo_scored' => ['integer', (int) $this->arePoolsWithHomogeneousScoredQuestionsRequired()],
180  'quest_amount_cfg_mode' => ['text', $this->getQuestionAmountConfigurationMode()],
181  'quest_amount_per_test' => ['integer', (int) $this->getQuestionAmountPerTest()],
182  'quest_sync_timestamp' => ['integer', (int) $this->getLastQuestionSyncTimestamp()]
183  ],
184  [
185  'test_fi' => ['integer', $test_id]
186  ]
187  );
188  }
189 
190  private function insertDbRecord(int $test_id): void
191  {
192  $this->db->insert(
193  'tst_rnd_quest_set_cfg',
194  [
195  'test_fi' => ['integer', $test_id],
196  'req_pools_homo_scored' => ['integer', (int) $this->arePoolsWithHomogeneousScoredQuestionsRequired()],
197  'quest_amount_cfg_mode' => ['text', $this->getQuestionAmountConfigurationMode()],
198  'quest_amount_per_test' => ['integer', (int) $this->getQuestionAmountPerTest()],
199  'quest_sync_timestamp' => ['integer', (int) $this->getLastQuestionSyncTimestamp()]
200  ]
201  );
202  }
203 
204  public function isQuestionSetConfigured(): bool
205  {
206  return $this->getLastQuestionSyncTimestamp() != 0
208  && $this->hasSourcePoolDefinitions()
209  && $this->isQuestionSetBuildable();
210  }
211 
212  public function isQuestionAmountConfigComplete(): bool
213  {
215  $sourcePoolDefinitionList = $this->buildSourcePoolDefinitionList($this->test_obj);
216 
217  $sourcePoolDefinitionList->loadDefinitions();
218 
219  foreach ($sourcePoolDefinitionList as $definition) {
220  if ($definition->getQuestionAmount() < 1) {
221  return false;
222  }
223  }
224  } elseif ($this->getQuestionAmountPerTest() < 1) {
225  return false;
226  }
227 
228  return true;
229  }
230 
231  public function hasSourcePoolDefinitions(): bool
232  {
233  return $this->buildSourcePoolDefinitionList($this->test_obj)
234  ->savedDefinitionsExist();
235  }
236 
237  public function isQuestionSetBuildable(): bool
238  {
239  $sourcePoolDefinitionList = $this->buildSourcePoolDefinitionList($this->test_obj);
240  $sourcePoolDefinitionList->loadDefinitions();
241 
242  $stagingPoolQuestionList = new ilTestRandomQuestionSetStagingPoolQuestionList($this->db, $this->component_repository);
243 
244  $questionSetBuilder = ilTestRandomQuestionSetBuilder::getInstance(
245  $this->db,
246  $this->lng,
247  $this->logger,
248  $this->test_obj,
249  $this,
250  $sourcePoolDefinitionList,
251  $stagingPoolQuestionList
252  );
253 
254  $buildable = $questionSetBuilder->checkBuildable();
255  $this->buildableMessages = $questionSetBuilder->getCheckMessages();
256  return $buildable;
257  }
258 
259  public function doesQuestionSetRelatedDataExist(): bool
260  {
261  if ($this->dbRecordExists($this->test_obj->getTestId())) {
262  return true;
263  }
264 
265  $sourcePoolDefinitionList = $this->buildSourcePoolDefinitionList($this->test_obj);
266 
267  if ($sourcePoolDefinitionList->savedDefinitionsExist()) {
268  return true;
269  }
270 
271  return false;
272  }
273 
274  public function removeQuestionSetRelatedData(): void
275  {
276  $sourcePoolDefinitionList = $this->buildSourcePoolDefinitionList($this->test_obj);
277  $sourcePoolDefinitionList->deleteDefinitions();
278 
280  $this->db,
281  $this->logger,
282  $this->test_obj
283  );
284  $stagingPool->reset();
285 
286  $this->deleteFromDb();
287  }
288 
289  public function cloneQuestionSetRelatedData(ilObjTest $clone_test_obj): void
290  {
291  $this->loadFromDb();
292  $this->cloneToDbForTestId($clone_test_obj->getTestId());
293 
294  // clone source pool definitions (selection rules)
295 
296  $source_pool_definition_list_orig = $this->buildSourcePoolDefinitionList($this->test_obj);
297  $source_pool_definition_list_orig->loadDefinitions();
298  $definition_id_map = $source_pool_definition_list_orig->cloneDefinitionsForTestId($clone_test_obj->getTestId());
299  $this->registerClonedSourcePoolDefinitionIdMapping($clone_test_obj, $definition_id_map);
300 
301  // build new question stage for cloned test
302 
303  $source_pool_definition_list_clone = $this->buildSourcePoolDefinitionList($clone_test_obj);
304  $staging_pool = $this->buildStagingPoolBuilder($clone_test_obj);
305 
306  $source_pool_definition_list_clone->loadDefinitions();
307  $staging_pool->rebuild($source_pool_definition_list_clone);
308  $source_pool_definition_list_clone->saveDefinitions();
309 
310  $this->updateLastQuestionSyncTimestampForTestId($clone_test_obj->getTestId(), time());
311  }
312 
313  private function registerClonedSourcePoolDefinitionIdMapping(ilObjTest $cloneTestOBJ, array $definitionIdMap): void
314  {
316 
317  foreach ($definitionIdMap as $originalDefinitionId => $cloneDefinitionId) {
318  $originalKey = $this->test_obj->getRefId() . '_rndSelDef_' . $originalDefinitionId;
319  $mappedKey = $cloneTestOBJ->getRefId() . '_rndSelDef_' . $cloneDefinitionId;
320  $cwo->appendMapping($originalKey, $mappedKey);
321  $this->logger->info(__METHOD__ . ": Added random selection definition id mapping $originalKey <-> $mappedKey");
322  }
323  }
324 
326  {
328  $this->db,
329  $test_obj,
331  $this->db,
332  $test_obj
333  )
334  );
335  }
336 
338  {
339  $stagingPool = new ilTestRandomQuestionSetStagingPoolBuilder($this->db, $this->logger, $test_obj);
340 
341  return $stagingPool;
342  }
343 
344  public function updateLastQuestionSyncTimestampForTestId(int $test_id, int $timestamp): void
345  {
346  $this->db->update(
347  'tst_rnd_quest_set_cfg',
348  [
349  'quest_sync_timestamp' => ['integer', (int) $timestamp]
350  ],
351  [
352  'test_fi' => ['integer', $test_id]
353  ]
354  );
355  }
356 
357  public function isResultTaxonomyFilterSupported(): bool
358  {
359  return true;
360  }
361 
362  public function getSelectableQuestionPools(): array
363  {
364  return $this->test_obj->getAvailableQuestionpools(
365  true,
367  false,
368  true,
369  true
370  );
371  }
372 
373  public function doesSelectableQuestionPoolsExist(): bool
374  {
375  return (bool) count($this->getSelectableQuestionPools());
376  }
377 
379  {
380  $definitionList = $this->buildSourcePoolDefinitionList($this->test_obj);
381  $definitionList->loadDefinitions();
382 
383  $poolTitles = [];
384 
385  foreach ($definitionList as $definition) {
386  $refId = current(ilObject::_getAllReferences($definition->getPoolId()));
387  $href = ilLink::_getLink($refId, 'qpl');
388  $title = $definition->getPoolTitle();
389 
390  $poolTitles[$definition->getPoolId()] = "<a href=\"$href\" alt=\"$title\">$title</a>";
391  }
392 
393  return implode(', ', $poolTitles);
394  }
395 }
setQuestionAmountPerTest(?int $questionAmountPerTest)
$res
Definition: ltiservices.php:69
updateLastQuestionSyncTimestampForTestId(int $test_id, int $timestamp)
static _getAllReferences(int $id)
get all reference ids for object ID
getTestId()
Gets the database id of the additional test data.
static getInstance(ilDBInterface $db, ilLanguage $lng, TestLogger $logger, ilObjTest $testOBJ, ilTestRandomQuestionSetConfig $questionSetConfig, ilTestRandomQuestionSetSourcePoolDefinitionList $sourcePoolDefinitionList, ilTestRandomQuestionSetStagingPoolQuestionList $stagingPoolQuestionList)
$refId
Definition: xapitoken.php:56
setLastQuestionSyncTimestamp(int $lastQuestionSyncTimestamp)
registerClonedSourcePoolDefinitionIdMapping(ilObjTest $cloneTestOBJ, array $definitionIdMap)
setPoolsWithHomogeneousScoredQuestionsRequired(bool $requirePoolsWithHomogeneousScoredQuestions)
setQuestionAmountConfigurationMode(?string $questionAmountConfigurationMode)
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
static _getInstance(int $a_copy_id)