ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.assFormulaQuestion.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
23
32{
33 private array $variables;
34 private array $results;
35 private array $resultunits;
38
39 public function __construct(
40 string $title = "",
41 string $comment = "",
42 string $author = "",
43 int $owner = -1,
44 string $question = ""
45 ) {
47 $this->variables = [];
48 $this->results = [];
49 $this->resultunits = [];
50 $this->unitrepository = new ilUnitConfigurationRepository(0);
51 $this->pass_presented_variables_repo = new PassPresentedVariablesRepo($this->db);
52 }
53
54 public function clearVariables(): void
55 {
56 $this->variables = [];
57 }
58
59 public function getVariables(): array
60 {
61 return $this->variables;
62 }
63
64 public function getVariable(string $variable): ?assFormulaQuestionVariable
65 {
66 if (array_key_exists($variable, $this->variables)) {
67 return $this->variables[$variable];
68 }
69 return null;
70 }
71
72 public function addVariable(assFormulaQuestionVariable $variable): void
73 {
74 $this->variables[$variable->getVariable()] = $variable;
75 }
76
77 public function clearResults(): void
78 {
79 $this->results = [];
80 }
81
82 public function getResults(): array
83 {
84 return $this->results;
85 }
86
87 public function getResult(string $result): ?assFormulaQuestionResult
88 {
89 if (array_key_exists($result, $this->results)) {
90 return $this->results[$result];
91 }
92 return null;
93 }
94
95 public function addResult(assFormulaQuestionResult $result): void
96 {
97 $this->results[$result->getResult()] = $result;
98 }
99
100 public function addResultUnits(
102 ?array $unit_ids
103 ): void {
104 $this->resultunits[$result->getResult()] = [];
105 if ($result === null || $unit_ids === null) {
106 return;
107 }
108 foreach ($unit_ids as $id) {
109 if (is_numeric($id) && ($id > 0)) {
110 $this->resultunits[$result->getResult()][$id] = $this->getUnitrepository()->getUnit($id);
111 }
112 }
113 }
114
115 public function addResultUnit(
118 ): void {
119 if ($result === null || $unit === null) {
120 return;
121 }
122
123 if (!array_key_exists($result->getResult(), $this->resultunits) ||
124 !is_array($this->resultunits[$result->getResult()])) {
125 $this->resultunits[$result->getResult()] = [];
126 }
127 $this->resultunits[$result->getResult()][$unit->getId()] = $unit;
128 }
129
130 public function getResultUnits(assFormulaQuestionResult $result): array
131 {
132 if (!isset($this->resultunits[$result->getResult()])) {
133 return [];
134 }
135
136 $result_units = $this->resultunits[$result->getResult()];
137
138 usort(
139 $result_units,
141 $a->getSequence() <=> $b->getSequence()
142 );
143
144 return $result_units;
145 }
146
147 public function getAllResultUnits(): array
148 {
149 return $this->resultunits;
150 }
151
152 public function hasResultUnit(
154 int $unit_id
155 ): bool {
156 if (array_key_exists($result->getResult(), $this->resultunits)
157 && array_key_exists($unit_id, $this->resultunits[$result->getResult()])) {
158 return true;
159 }
160
161 return false;
162 }
163
164 public function parseQuestionText(): void
165 {
166 $this->clearResults();
167 $this->clearVariables();
168 if (preg_match_all('/(\$v\d+)/im', $this->getQuestion(), $matches)) {
169 foreach ($matches[1] as $variable) {
170 $varObj = new assFormulaQuestionVariable($variable, '0.0', '0.0', null, 0);
171 $this->addVariable($varObj);
172 }
173 }
174
175 if (preg_match_all('/(\$r\d+)/im', $this->getQuestion(), $rmatches)) {
176 foreach ($rmatches[1] as $result) {
177 $resObj = new assFormulaQuestionResult($result, null, null, 0, null, null, 1, 1, true);
178 $this->addResult($resObj);
179 }
180 }
181 }
182
183 public function checkForDuplicateVariables(): bool
184 {
185 if (preg_match_all('/(\$v\d+)/im', $this->getQuestion(), $matches)) {
186 if ((count(array_unique($matches[1]))) != count($matches[1])) {
187 return false;
188 }
189 }
190 return true;
191 }
192
193 public function checkForDuplicateResults(): bool
194 {
195 if (preg_match_all('/(\$r\d+)/im', $this->getQuestion(), $rmatches)) {
196 if ((count(array_unique($rmatches[1]))) != count($rmatches[1])) {
197 return false;
198 }
199 }
200 return true;
201 }
202
207 public function fetchAllResults($questionText): array
208 {
209 $resObjects = [];
210 $matches = null;
211
212 if (preg_match_all('/(\$r\d+)/im', $questionText, $matches)) {
213 foreach ($matches[1] as $resultKey) {
214 $resObjects[] = $this->getResult($resultKey);
215 }
216 }
217
218 return $resObjects;
219 }
220
224 public function fetchAllVariables(string $question_text): array
225 {
226 $var_objects = [];
227 $matches = null;
228
229 if (preg_match_all('/(\$v\d+)/im', $question_text, $matches)) {
230 $var_objects = array_reduce(
231 $matches[1],
232 function (array $c, string $v): array {
233 $vo = $this->getVariable($v);
234 if ($vo !== null) {
235 $c[] = $vo;
236 }
237 return $c;
238 },
239 []
240 );
241 }
242
243 return $var_objects;
244 }
245
250 public function hasRequiredVariableSolutionValues(array $userSolution): bool
251 {
252 foreach ($this->fetchAllVariables($this->getQuestion()) as $varObj) {
253 if (!isset($userSolution[$varObj->getVariable()])) {
254 return false;
255 }
256
257 if ($userSolution[$varObj->getVariable()] === '') {
258 return false;
259 }
260 }
261
262 return true;
263 }
264
266 int $active_id,
267 int $pass
268 ): array {
269 $question_id = $this->getId();
270 $values = $this->pass_presented_variables_repo->getFor(
271 $question_id,
272 $active_id,
273 $pass
274 );
275 if (is_null($values)) {
276 $values = $this->getInitialVariableSolutionValues();
277 $this->pass_presented_variables_repo->store(
278 $question_id,
279 $active_id,
280 $pass,
281 $values
282 );
283 }
284 return $values;
285 }
286
287 public function getInitialVariableSolutionValues(): array
288 {
289 foreach ($this->fetchAllResults($this->getQuestion()) as $resObj) {
290 $resObj->findValidRandomVariables($this->getVariables(), $this->getResults());
291 }
292
293 $variableSolutionValues = [];
294
295 foreach ($this->fetchAllVariables($this->getQuestion()) as $varObj) {
296 $variableSolutionValues[$varObj->getVariable()] = $varObj->getValue();
297 }
298
299 return $variableSolutionValues;
300 }
301
302 public function saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized = true, $tstamp = 0): int
303 {
304 $init_solution_vars = $this->getVariableSolutionValuesForPass($active_id, $pass);
305 foreach ($init_solution_vars as $val1 => $val2) {
306 $this->db->manipulateF(
307 "DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s AND value1 = %s",
308 ['integer', 'integer','integer', 'text'],
309 [$active_id, $this->getId(), $pass, $val1]
310 );
311 parent::saveCurrentSolution($active_id, $pass, $val1, $val2, $authorized);
312 }
313 return parent::saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized, $tstamp);
314 }
315
321 public function substituteVariables(array $userdata, bool $graphicalOutput = false, bool $forsolution = false, bool $result_output = false, array $correctness_icons = [])
322 {
323 if ((count($this->results) == 0) && (count($this->variables) == 0)) {
324 return false;
325 }
326
327 $text = $this->getQuestion();
328
329 foreach ($this->fetchAllVariables($this->getQuestion()) as $varObj) {
330 if (isset($userdata[$varObj->getVariable()]) && strlen($userdata[$varObj->getVariable()])) {
331 $varObj->setValue($userdata[$varObj->getVariable()]);
332 }
333
334 $unit = (is_object($varObj->getUnit())) ? $varObj->getUnit()->getUnit() : "";
335
336 $val = '';
337 if ($varObj->getValue() !== null) {
338 $val = (strlen($varObj->getValue()) > 8) ? strtoupper(sprintf("%e", $varObj->getValue())) : $varObj->getValue();
339 }
340
341 $text = preg_replace('/\$' . substr($varObj->getVariable(), 1) . '(?![0-9]+)/', $val . ' ' . $unit . '\1', $text);
342 }
343
344 $text = $this->purifyAndPrepareTextAreaOutput($text);
345
346 if (preg_match_all('/(\$r\d+)/im', $this->getQuestion(), $rmatches)) {
347 foreach ($rmatches[1] as $result) {
348 $resObj = $this->getResult($result);
349 $value = "";
350 $frac_helper = '';
351 $userdata[$result]['result_type'] = $resObj->getResultType();
352 $is_frac = false;
353 if (
354 $resObj->getResultType() == assFormulaQuestionResult::RESULT_FRAC ||
355 $resObj->getResultType() == assFormulaQuestionResult::RESULT_CO_FRAC
356 ) {
357 $is_frac = true;
358 }
359 if (is_array($userdata) &&
360 isset($userdata[$result]) &&
361 isset($userdata[$result]['value'])) {
362 $input = $this->generateResultInputHTML($result, (string) $userdata[$result]['value'], $forsolution);
363 } elseif ($forsolution) {
364 $value = '';
365 if (!is_array($userdata)) {
366 $value = $resObj->calculateFormula($this->getVariables(), $this->getResults(), parent::getId());
367 $value = sprintf("%." . $resObj->getPrecision() . "f", $value);
368 }
369
370 if ($is_frac) {
372 if (is_array($value)) {
373 $frac_helper = $value[1];
374 $value = $value[0];
375 }
376 }
377
378 $input = $this->generateResultInputHTML($result, $value, true);
379 } else {
380 $input = $this->generateResultInputHTML($result, '', false);
381 }
382
383 $units = "";
384 $result_units = $this->getResultUnits($resObj);
385 if (count($result_units) > 0) {
386 if ($forsolution) {
387 if (is_array($userdata)) {
388 foreach ($result_units as $unit) {
389 if (isset($userdata[$result]["unit"]) && $userdata[$result]["unit"] == $unit->getId()) {
390 $units = $unit->getUnit();
391 }
392 }
393 } else {
394 if ($resObj->getUnit()) {
395 $units = $resObj->getUnit()->getUnit();
396 }
397 }
398 } else {
399 $units = '<select name="result_' . $result . '_unit">';
400 $units .= '<option value="-1">' . $this->lng->txt("select_unit") . '</option>';
401 foreach ($result_units as $unit) {
402 $units .= '<option value="' . $unit->getId() . '"';
403 if (array_key_exists($result, $userdata) &&
404 is_array($userdata[$result]) &&
405 array_key_exists('unit', $userdata[$result])) {
406 if ($userdata[$result]["unit"] == $unit->getId()) {
407 $units .= ' selected="selected"';
408 }
409 }
410 $units .= '>' . $unit->getUnit() . '</option>';
411 }
412 $units .= '</select>';
413 }
414 } else {
415 $units = "";
416 }
417 switch ($resObj->getResultType()) {
419 $units .= ' ' . $this->lng->txt('expected_result_type') . ': ' . $this->lng->txt('result_dec');
420 break;
422 if ($frac_helper !== '') {
423 $units .= ' &asymp; ' . $frac_helper . ', ';
424 } elseif (is_array($userdata) &&
425 array_key_exists($result, $userdata) &&
426 array_key_exists('frac_helper', $userdata[$result]) &&
427 is_string($userdata[$result]["frac_helper"])) {
428 if (!str_contains($value, '/')) {
429 $units .= ' &asymp; ' . $userdata[$result]["frac_helper"] . ', ';
430 }
431 }
432 $units .= ' ' . $this->lng->txt('expected_result_type') . ': ' . $this->lng->txt('result_frac');
433 break;
435 if ($frac_helper !== '') {
436 $units .= ' &asymp; ' . $frac_helper . ', ';
437 } elseif (isset($userdata[$result]["frac_helper"]) && is_array($userdata) && $userdata[$result]["frac_helper"] !== '') {
438 if (!str_contains($value, '/')) {
439 $units .= ' &asymp; ' . $userdata[$result]["frac_helper"] . ', ';
440 }
441 }
442 $units .= ' ' . $this->lng->txt('expected_result_type') . ': ' . $this->lng->txt('result_co_frac');
443 break;
445 break;
446 }
447 $checkSign = "";
448 if ($graphicalOutput) {
449 $resunit = null;
450 $user_value = '';
451 if (is_array($userdata) && is_array($userdata[$result])) {
452 if (isset($userdata[$result]["unit"]) && $userdata[$result]["unit"] > 0) {
453 $resunit = $this->getUnitrepository()->getUnit($userdata[$result]["unit"]);
454 }
455
456 if (isset($userdata[$result]["value"])) {
457 $user_value = $userdata[$result]["value"];
458 }
459 }
460
461 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output_solution_image.html", true, true, 'components/ILIAS/TestQuestionPool');
462
463 $correctness_icon = $correctness_icons['not_correct'];
464 if ($resObj->isCorrect($this->getVariables(), $this->getResults(), $user_value, $resunit)) {
465 $correctness_icon = $correctness_icons['correct'];
466 }
467 $template->setCurrentBlock("icon_ok");
468 $template->setVariable("ICON_OK", $correctness_icon);
469 $template->parseCurrentBlock();
470
471 $checkSign = $template->get();
472 }
473 $resultOutput = "";
474 if ($result_output) {
475 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output_solution_result.html", true, true, 'components/ILIAS/TestQuestionPool');
476
477 if (is_array($userdata) &&
478 array_key_exists($resObj->getResult(), $userdata) &&
479 array_key_exists('value', $userdata[$resObj->getResult()])) {
480 $found = $resObj->getResultInfo(
481 $this->getVariables(),
482 $this->getResults(),
483 $userdata[$resObj->getResult()]["value"],
484 $userdata[$resObj->getResult()]["unit"] ?? null,
485 $this->getUnitrepository()->getUnits()
486 );
487 } else {
488 $found = $resObj->getResultInfo(
489 $this->getVariables(),
490 $this->getResults(),
491 $resObj->calculateFormula($this->getVariables(), $this->getResults(), parent::getId()),
492 is_object($resObj->getUnit()) ? $resObj->getUnit()->getId() : null,
493 $this->getUnitrepository()->getUnits()
494 );
495 }
496 $resulttext = "(";
497 if ($resObj->getRatingSimple()) {
498 if ($frac_helper) {
499 $resulttext .= "n/a";
500 } else {
501 $resulttext .= $found['points'] . " " . (($found['points'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points'));
502 }
503 } else {
504 $resulttext .= $this->lng->txt("rated_sign") . " " . (($found['sign']) ? $found['sign'] : 0) . " " . (($found['sign'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points')) . ", ";
505 $resulttext .= $this->lng->txt("rated_value") . " " . (($found['value']) ? $found['value'] : 0) . " " . (($found['value'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points')) . ", ";
506 $resulttext .= $this->lng->txt("rated_unit") . " " . (($found['unit']) ? $found['unit'] : 0) . " " . (($found['unit'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points'));
507 }
508
509 $resulttext .= ")";
510 $template->setVariable("RESULT_OUTPUT", $resulttext);
511
512 $resultOutput = $template->get();
513 }
514 $text = preg_replace('/\$' . substr($result, 1) . '(?![0-9]+)/', $input . ' ' . $units . ' ' . $checkSign . ' ' . $resultOutput . ' ' . '\1', $text);
515 }
516 }
517 return $text;
518 }
519
520 protected function generateResultInputHTML(string $result_key, string $result_value, bool $forsolution): string
521 {
522 if ($forsolution) {
523 return '<span class="ilc_qinput_TextInput solutionbox">'
525 . '</span>';
526 }
527 $input = '<input class="ilc_qinput_TextInput" type="text"';
528 $input .= 'spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"';
529 $input .= 'name="result_' . $result_key . '"';
530 $input .= ' value="' . $result_value . '"/>';
531 return $input;
532 }
533
540 public function canUseAdvancedRating($result): bool
541 {
542 $result_units = $this->getResultUnits($result);
543 $resultunit = $result->getUnit();
544 $similar_units = 0;
545 foreach ($result_units as $unit) {
546 if (is_object($resultunit)) {
547 if ($resultunit->getId() != $unit->getId()) {
548 if ($resultunit->getBaseUnit() && $unit->getBaseUnit()) {
549 if ($resultunit->getBaseUnit() == $unit->getBaseUnit()) {
550 return false;
551 }
552 }
553 if ($resultunit->getBaseUnit()) {
554 if ($resultunit->getBaseUnit() == $unit->getId()) {
555 return false;
556 }
557 }
558 if ($unit->getBaseUnit()) {
559 if ($unit->getBaseUnit() == $resultunit->getId()) {
560 return false;
561 }
562 }
563 }
564 }
565 }
566 return true;
567 }
568
573 public function isComplete(): bool
574 {
575 if (($this->title) and ($this->author) and ($this->question) and ($this->getMaximumPoints() > 0)) {
576 return true;
577 } else {
578 return false;
579 }
580 }
581
582 public function saveToDb(?int $original_id = null): void
583 {
584 $this->saveQuestionDataToDb($original_id);
585 // save variables
586 $affectedRows = $this->db->manipulateF(
587 "
588 DELETE FROM il_qpl_qst_fq_var
589 WHERE question_fi = %s",
590 ['integer'],
591 [$this->getId()]
592 );
593
594 foreach ($this->variables as $variable) {
595 $next_id = $this->db->nextId('il_qpl_qst_fq_var');
596 $this->db->insert(
597 'il_qpl_qst_fq_var',
598 [
599 'variable_id' => ['integer', $next_id],
600 'question_fi' => ['integer', $this->getId()],
601 'variable' => ['text', $variable->getVariable()],
602 'range_min' => ['float', $variable->getRangeMin()],
603 'range_max' => ['float', $variable->getRangeMax()],
604 'unit_fi' => ['integer', (is_object($variable->getUnit()) ? (int) $variable->getUnit()->getId() : 0)],
605 'varprecision' => ['integer', (int) $variable->getPrecision()],
606 'intprecision' => ['integer', (int) $variable->getIntprecision()],
607 'range_min_txt' => ['text', $variable->getRangeMinTxt()],
608 'range_max_txt' => ['text', $variable->getRangeMaxTxt()]
609 ]
610 );
611 }
612 // save results
613 $affectedRows = $this->db->manipulateF(
614 "DELETE FROM il_qpl_qst_fq_res WHERE question_fi = %s",
615 ['integer'],
616 [$this->getId()]
617 );
618
619 foreach ($this->results as $result) {
620 $next_id = $this->db->nextId('il_qpl_qst_fq_res');
621 if (is_object($result->getUnit())) {
622 $tmp_result_unit = $result->getUnit()->getId();
623 } else {
624 $tmp_result_unit = null;
625 }
626
627 $formula = null;
628 if ($result->getFormula() !== null) {
629 $formula = str_replace(",", ".", $result->getFormula());
630 }
631
632 $this->db->insert("il_qpl_qst_fq_res", [
633 "result_id" => ['integer', $next_id],
634 "question_fi" => ['integer', $this->getId()],
635 "result" => ["text", $result->getResult()],
636 "range_min" => ["float", $result->getRangeMin()],
637 "range_max" => ["float", $result->getRangeMax()],
638 "tolerance" => ["float", $result->getTolerance()],
639 "unit_fi" => ['integer', (int) $tmp_result_unit],
640 "formula" => ["clob", $formula],
641 "resprecision" => ['integer', $result->getPrecision()],
642 "rating_simple" => ['integer', ($result->getRatingSimple()) ? 1 : 0],
643 "rating_sign" => ["float", ($result->getRatingSimple()) ? 0 : $result->getRatingSign()],
644 "rating_value" => ["float", ($result->getRatingSimple()) ? 0 : $result->getRatingValue()],
645 "rating_unit" => ["float", ($result->getRatingSimple()) ? 0 : $result->getRatingUnit()],
646 "points" => ["float", $result->getPoints()],
647 "result_type" => ['integer', (int) $result->getResultType()],
648 "range_min_txt" => ["text", $result->getRangeMinTxt()],
649 "range_max_txt" => ["text", $result->getRangeMaxTxt()]
650
651 ]);
652 }
653 // save result units
654 $affectedRows = $this->db->manipulateF(
655 "DELETE FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
656 ['integer'],
657 [$this->getId()]
658 );
659 foreach ($this->results as $result) {
660 foreach ($this->getResultUnits($result) as $unit) {
661 $next_id = $this->db->nextId('il_qpl_qst_fq_res_unit');
662 $affectedRows = $this->db->manipulateF(
663 "INSERT INTO il_qpl_qst_fq_res_unit (result_unit_id, question_fi, result, unit_fi) VALUES (%s, %s, %s, %s)",
664 ['integer', 'integer', 'text', 'integer'],
665 [
666 $next_id,
667 $this->getId(),
668 $result->getResult(),
669 $unit->getId()
670 ]
671 );
672 }
673 }
674
675 parent::saveToDb();
676 }
677
678 public function loadFromDb(int $question_id): void
679 {
680 $result = $this->db->queryF(
681 "SELECT qpl_questions.* FROM qpl_questions WHERE question_id = %s",
682 ['integer'],
683 [$question_id]
684 );
685 if ($result->numRows() == 1) {
686 $data = $this->db->fetchAssoc($result);
687 $this->setId($question_id);
688 $this->setTitle((string) $data["title"]);
689 $this->setComment((string) $data["description"]);
690 $this->setPoints($data['points']);
691 $this->setOriginalId($data["original_id"]);
692 $this->setObjId($data["obj_fi"]);
693 $this->setAuthor($data["author"]);
694 $this->setOwner($data["owner"]);
695
696 try {
697 $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
699 $this->setLifecycle(ilAssQuestionLifecycle::getDraftInstance());
700 }
701
702 try {
703 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
705 }
706
707 $this->unitrepository = new ilUnitConfigurationRepository($question_id);
708
709 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
710
711 // load variables
712 $result = $this->db->queryF(
713 "SELECT * FROM il_qpl_qst_fq_var WHERE question_fi = %s",
714 ['integer'],
715 [$question_id]
716 );
717 if ($result->numRows() > 0) {
718 while ($data = $this->db->fetchAssoc($result)) {
719 $varObj = new assFormulaQuestionVariable(
720 $data['variable'],
721 $data['range_min_txt'],
722 $data['range_max_txt'],
723 $this->getUnitrepository()->getUnit($data['unit_fi']),
724 $data['varprecision'],
725 $data['intprecision']
726 );
727 $this->addVariable($varObj);
728 }
729 }
730 // load results
731 $result = $this->db->queryF(
732 "SELECT * FROM il_qpl_qst_fq_res WHERE question_fi = %s",
733 ['integer'],
734 [$question_id]
735 );
736 if ($result->numRows() > 0) {
737 while ($data = $this->db->fetchAssoc($result)) {
738 $resObj = new assFormulaQuestionResult(
739 $data['result'],
740 $data['range_min_txt'],
741 $data['range_max_txt'],
742 $data['tolerance'],
743 $this->getUnitrepository()->getUnit($data['unit_fi']),
744 $data['formula'],
745 $data['points'],
746 $data['resprecision'],
747 $data['rating_simple'] === 1,
748 $data['rating_sign'],
749 $data['rating_value'],
750 $data['rating_unit']
751 );
752 $resObj->setResultType($data['result_type']);
753 $this->addResult($resObj);
754 }
755 }
756
757 // load result units
758 $result = $this->db->queryF(
759 "SELECT * FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
760 ['integer'],
761 [$question_id]
762 );
763 if ($result->numRows() > 0) {
764 while ($data = $this->db->fetchAssoc($result)) {
765 $unit = $this->getUnitrepository()->getUnit($data["unit_fi"]);
766 $resObj = $this->getResult($data["result"]);
767 $this->addResultUnit($resObj, $unit);
768 }
769 }
770 }
771 parent::loadFromDb($question_id);
772 }
773
775 \assQuestion $target
776 ): \assQuestion {
777 $this->unitrepository->cloneUnits($this->getId(), $target->getId());
778 return $target;
779 }
780
785 public function getMaximumPoints(): float
786 {
787 $points = 0;
788 foreach ($this->results as $result) {
789 $points += $result->getPoints();
790 }
791 return $points;
792 }
793
794 public function calculateReachedPoints(
795 int $active_id,
796 ?int $pass = null,
797 bool $authorized_solution = true
798 ): float {
799 if ($pass === null) {
800 $pass = $this->getSolutionMaxPass($active_id);
801 }
802 $solutions = $this->getSolutionValues($active_id, $pass, $authorized_solution);
803 $user_solution = [];
804 foreach ($solutions as $solution_value) {
805 if (preg_match('/^(\$v\d+)$/', $solution_value['value1'], $matches)) {
806 $user_solution[$matches[1]] = $solution_value['value2'];
807 $var_obj = $this->getVariable($solution_value['value1']);
808 $var_obj->setValue($solution_value['value2']);
809 continue;
810 }
811
812 if (preg_match('/^(\$r\d+)$/', $solution_value['value1'], $matches)) {
813 if (!array_key_exists($matches[1], $user_solution)) {
814 $user_solution[$matches[1]] = [];
815 }
816 $user_solution[$matches[1]]['value'] = $solution_value['value2'];
817 continue;
818 }
819
820 if (preg_match('/^(\$r\d+)_unit$/', $solution_value['value1'], $matches)) {
821 if (!array_key_exists($matches[1], $user_solution)) {
822 $user_solution[$matches[1]] = [];
823 }
824 $user_solution[$matches[1]]['unit'] = $this->unitrepository->getUnit(
825 $this->refinery->kindlyTo()->int()->transform($solution_value['value2']),
826 );
827 }
828 }
829
830 $points = 0;
831 foreach ($this->getResults() as $result) {
832 $points += $result->getReachedPoints(
833 $this->getVariables(),
834 $this->getResults(),
835 $user_solution[$result->getResult()]['value'] ?? '',
836 $user_solution[$result->getResult()]['unit'] ?? null,
837 $this->unitrepository->getUnits()
838 );
839 }
840
841 return (float) $points;
842 }
843
845 {
846 $user_solution = $previewSession->getParticipantsSolution();
847
848 $points = 0;
849 foreach ($this->getResults() as $result) {
850 $unit_id = $user_solution[$result->getResult() . '_unit'] ?? null;
851 $points += $result->getReachedPoints(
852 $this->getVariables(),
853 $this->getResults(),
854 $user_solution[$result->getResult()] ?? '',
855 $unit_id !== null ? $this->unitrepository->getUnit($unit_id) : null,
856 $this->unitrepository->getUnits()
857 );
858 }
859 return $this->ensureNonNegativePoints($points);
860 }
861
862 protected function isValidSolutionResultValue(string $submittedValue): bool
863 {
864 $submittedValue = str_replace(',', '.', $submittedValue);
865
866 if (is_numeric($submittedValue)) {
867 return true;
868 }
869
870 if (preg_match('/^[-+]?\d+\/\d+$/', $submittedValue)) {
871 return true;
872 }
873
874 return false;
875 }
876
877 public function saveWorkingData(
878 int $active_id,
879 ?int $pass = null,
880 bool $authorized = true
881 ): bool {
882 if (is_null($pass)) {
883 $pass = ilObjTest::_getPass($active_id);
884 }
885
886 $answer = $this->getSolutionSubmit();
887 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
888 function () use ($answer, $active_id, $pass, $authorized) {
889 foreach ($answer as $key => $value) {
890 $matches = null;
891 if (preg_match('/^result_(\$r\d+)$/', $key, $matches) !== false) {
892 $queryResult = "SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND authorized = %s AND " . $this->db->like('value1', 'clob', $matches[1]);
893
894 if ($this->getStep() !== null) {
895 $queryResult .= " AND step = " . $this->db->quote((int) $this->getStep(), 'integer') . " ";
896 }
897
898 $result = $this->db->queryF(
899 $queryResult,
900 ['integer', 'integer', 'integer', 'integer'],
901 [$active_id, $pass, $this->getId(), (int) $authorized]
902 );
903 if ($result->numRows()) {
904 while ($row = $this->db->fetchAssoc($result)) {
905 $this->db->manipulateF(
906 "DELETE FROM tst_solutions WHERE solution_id = %s AND authorized = %s",
907 ['integer', 'integer'],
908 [$row['solution_id'], (int) $authorized]
909 );
910 }
911 }
912
913 $this->saveCurrentSolution($active_id, $pass, $matches[1], str_replace(",", ".", $value), $authorized);
914 continue;
915 }
916
917 if (preg_match('/^result_(\$r\d+)_unit$/', $key, $matches) !== false) {
918 $queryResultUnit = "SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND authorized = %s AND " . $this->db->like('value1', 'clob', $matches[1] . "_unit");
919
920 if ($this->getStep() !== null) {
921 $queryResultUnit .= " AND step = " . $this->db->quote((int) $this->getStep(), 'integer') . " ";
922 }
923
924 $result = $this->db->queryF(
925 $queryResultUnit,
926 ['integer', 'integer', 'integer', 'integer'],
927 [$active_id, $pass, $this->getId(), (int) $authorized]
928 );
929 if ($result->numRows()) {
930 while ($row = $this->db->fetchAssoc($result)) {
931 $this->db->manipulateF(
932 "DELETE FROM tst_solutions WHERE solution_id = %s AND authorized = %s",
933 ['integer', 'integer'],
934 [$row['solution_id'], (int) $authorized]
935 );
936 }
937 }
938
939 $this->saveCurrentSolution($active_id, $pass, $matches[1] . "_unit", $value, $authorized);
940 }
941 }
942 }
943 );
944
945 return true;
946 }
947
951 public function lookupForExistingSolutions(int $active_id, int $pass): array
952 {
953 $return = [
954 'authorized' => false,
955 'intermediate' => false
956 ];
957
958 $query = "
959 SELECT authorized, COUNT(*) cnt
960 FROM tst_solutions
961 WHERE active_fi = " . $this->db->quote($active_id, 'integer') . "
962 AND question_fi = " . $this->db->quote($this->getId(), 'integer') . "
963 AND pass = " . $this->db->quote($pass, 'integer') . "
964 AND value1 like '\$r%'
965 AND value2 is not null
966 AND value2 <> ''
967 ";
968
969 if ($this->getStep() !== null) {
970 $query .= " AND step = " . $this->db->quote((int) $this->getStep(), 'integer') . " ";
971 }
972
973 $query .= "
974 GROUP BY authorized
975 ";
976
977 $result = $this->db->query($query);
978
979 while ($row = $this->db->fetchAssoc($result)) {
980 if ($row['authorized']) {
981 $return['authorized'] = $row['cnt'] > 0;
982 } else {
983 $return['intermediate'] = $row['cnt'] > 0;
984 }
985 }
986 return $return;
987 }
988
989 public function removeExistingSolutions(int $active_id, int $pass): int
990 {
991 $query = "
992 DELETE FROM tst_solutions
993 WHERE active_fi = " . $this->db->quote($active_id, 'integer') . "
994 AND question_fi = " . $this->db->quote($this->getId(), 'integer') . "
995 AND pass = " . $this->db->quote($pass, 'integer') . "
996 AND value1 like '\$r%'
997 ";
998
999 if ($this->getStep() !== null) {
1000 $query .= " AND step = " . $this->db->quote((int) $this->getStep(), 'integer') . " ";
1001 }
1002
1003 return $this->db->manipulate($query);
1004 }
1005
1006 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
1007 {
1008 $userSolution = $previewSession->getParticipantsSolution();
1009
1010 foreach ($this->getSolutionSubmit() as $key => $val) {
1011 $matches = null;
1012
1013 if (preg_match('/^result_(\$r\d+)$/', $key, $matches)) {
1014 $userSolution[$matches[1]] = $val;
1015 } elseif (preg_match('/^result_(\$r\d+)_unit$/', $key, $matches)) {
1016 $userSolution[$matches[1] . "_unit"] = $val;
1017 }
1018 }
1019
1020 $previewSession->setParticipantsSolution($userSolution);
1021 }
1022
1023 public function getQuestionType(): string
1024 {
1025 return "assFormulaQuestion";
1026 }
1027
1028 public function getAdditionalTableName(): string
1029 {
1030 return "";
1031 }
1032
1033 public function getAnswerTableName(): string
1034 {
1035 return "";
1036 }
1037
1038 public function deleteAnswers(int $question_id): void
1039 {
1040 $affectedRows = $this->db->manipulateF(
1041 "DELETE FROM il_qpl_qst_fq_var WHERE question_fi = %s",
1042 ['integer'],
1043 [$question_id]
1044 );
1045
1046 $affectedRows = $this->db->manipulateF(
1047 "DELETE FROM il_qpl_qst_fq_res WHERE question_fi = %s",
1048 ['integer'],
1049 [$question_id]
1050 );
1051
1052 $affectedRows = $this->db->manipulateF(
1053 "DELETE FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
1054 ['integer'],
1055 [$question_id]
1056 );
1057
1058 $affectedRows = $this->db->manipulateF(
1059 "DELETE FROM il_qpl_qst_fq_ucat WHERE question_fi = %s",
1060 ['integer'],
1061 [$question_id]
1062 );
1063
1064 $affectedRows = $this->db->manipulateF(
1065 "DELETE FROM il_qpl_qst_fq_unit WHERE question_fi = %s",
1066 ['integer'],
1067 [$question_id]
1068 );
1069 }
1070
1071 public function getRTETextWithMediaObjects(): string
1072 {
1073 $text = parent::getRTETextWithMediaObjects();
1074 return $text;
1075 }
1076
1077 public function getBestSolution(array $solutions): array
1078 {
1079 $user_solution = [];
1080
1081 foreach ($solutions as $solution_value) {
1082 if (preg_match('/^(\$v\d+)$/', $solution_value['value1'], $matches)) {
1083 $user_solution[$matches[1]] = $solution_value['value2'];
1084 $varObj = $this->getVariable($matches[1]);
1085 $varObj->setValue($solution_value['value2']);
1086 } elseif (preg_match('/^(\$r\d+)$/', $solution_value['value1'], $matches)) {
1087 if (!array_key_exists($matches[1], $user_solution)) {
1088 $user_solution[$matches[1]] = [];
1089 }
1090 $user_solution[$matches[1]]['value'] = $solution_value['value2'];
1091 } elseif (preg_match('/^(\$r\d+)_unit$/', $solution_value['value1'], $matches)) {
1092 if (!array_key_exists($matches[1], $user_solution)) {
1093 $user_solution[$matches[1]] = [];
1094 }
1095 $user_solution[$matches[1]]['unit'] = $solution_value['value2'];
1096 }
1097 }
1098 foreach ($this->getResults() as $result) {
1099 $resVal = $result->calculateFormula($this->getVariables(), $this->getResults(), $this->getId(), false);
1100
1101 if (is_object($result->getUnit())) {
1102 $user_solution[$result->getResult()]['unit'] = $result->getUnit()->getId();
1103 $user_solution[$result->getResult()]['value'] = $resVal;
1104 } elseif ($result->getUnit() === null) {
1105 $unit_factor = 1;
1106 // there is no fix result_unit, any "available unit" is accepted
1107
1108 $available_units = $result->getAvailableResultUnits(parent::getId());
1109 $result_name = $result->getResult();
1110
1111 $check_unit = false;
1112 if (array_key_exists($result_name, $available_units) &&
1113 $available_units[$result_name] !== null) {
1114 $check_unit = in_array($user_solution[$result_name]['unit'] ?? null, $available_units[$result_name]);
1115 }
1116
1117 if ($check_unit == true) {
1118 //get unit-factor
1119 $unit_factor = assFormulaQuestionUnit::lookupUnitFactor($user_solution[$result_name]['unit']);
1120 }
1121
1122 try {
1123 $user_solution[$result->getResult()]['value'] = ilMath::_div($resVal, $unit_factor, 55);
1124 } catch (ilMathDivisionByZeroException $ex) {
1125 $user_solution[$result->getResult()]['value'] = 0;
1126 }
1127 }
1128 if ($result->getResultType() == assFormulaQuestionResult::RESULT_CO_FRAC
1129 || $result->getResultType() == assFormulaQuestionResult::RESULT_FRAC) {
1131 if (is_array($value)) {
1132 $user_solution[$result->getResult()]['value'] = $value[0];
1133 $user_solution[$result->getResult()]['frac_helper'] = $value[1];
1134 } else {
1135 $user_solution[$result->getResult()]['value'] = $value;
1136 $user_solution[$result->getResult()]['frac_helper'] = null;
1137 }
1138 } else {
1139 $user_solution[$result->getResult()]['value'] = round((float) $user_solution[$result->getResult()]['value'], $result->getPrecision());
1140 }
1141 }
1142 return $user_solution;
1143 }
1144
1145 public function setId(int $id = -1): void
1146 {
1147 parent::setId($id);
1148 $this->unitrepository->setConsumerId($this->getId());
1149 }
1150
1151 public function setUnitrepository(\ilUnitConfigurationRepository $unitrepository): void
1152 {
1153 $this->unitrepository = $unitrepository;
1154 }
1155
1157 {
1158 return $this->unitrepository;
1159 }
1160
1164 protected function getSolutionSubmit(): array
1165 {
1166 $solutionSubmit = [];
1167
1168 $post = $this->dic->http()->wrapper()->post();
1169
1170 foreach ($this->getResults() as $index => $a) {
1171 $key = "result_$index";
1172 if ($post->has($key)) {
1173 $value = $post->retrieve(
1174 $key,
1175 $this->dic->refinery()->kindlyTo()->string()
1176 );
1177
1178 $solutionSubmit[$key] = $value;
1179 }
1180 if ($post->has($key . "_unit")) {
1181 $value = $post->retrieve(
1182 $key . "_unit",
1183 $this->dic->refinery()->kindlyTo()->string()
1184 );
1185 $solutionSubmit[$key . "_unit"] = $value;
1186 }
1187 }
1188 return $solutionSubmit;
1189 }
1190
1191 public function validateSolutionSubmit(): bool
1192 {
1193 foreach ($this->getSolutionSubmit() as $value) {
1194 if ($value && !$this->isValidSolutionResultValue($value)) {
1195 $this->tpl->setOnScreenMessage(
1196 'failure',
1197 $this->lng->txt("err_no_numeric_value"),
1198 true
1199 );
1200 return false;
1201 }
1202 }
1203
1204 return true;
1205 }
1206
1207 public function getOperators(string $expression): array
1208 {
1210 }
1211
1212 public function getExpressionTypes(): array
1213 {
1214 return [
1218 ];
1219 }
1220
1221 public function getUserQuestionResult(
1222 int $active_id,
1223 int $pass
1225 $result = new ilUserQuestionResult($this, $active_id, $pass);
1226
1227 $maxStep = $this->lookupMaxStep($active_id, $pass);
1228 if ($maxStep > 0) {
1229 $data = $this->db->queryF(
1230 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
1231 ['integer', 'integer', 'integer','integer'],
1232 [$active_id, $pass, $this->getId(), $maxStep]
1233 );
1234 } else {
1235 $data = $this->db->queryF(
1236 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
1237 ['integer', 'integer', 'integer'],
1238 [$active_id, $pass, $this->getId()]
1239 );
1240 }
1241
1242 while ($row = $this->db->fetchAssoc($data)) {
1243 if (strstr($row['value1'], '$r') && $row['value2'] != null) {
1244 $result->addKeyValue(str_replace('$r', "", $row['value1']), $row['value2']);
1245 }
1246 }
1247
1248 $points = $this->calculateReachedPoints($active_id, $pass);
1249 $max_points = $this->getMaximumPoints();
1250
1251 $result->setReachedPercentage(($points / $max_points) * 100);
1252
1253 return $result;
1254 }
1255
1264 public function getAvailableAnswerOptions($index = null)
1265 {
1266 if ($index !== null) {
1267 return $this->getResult('$r' . ($index + 1));
1268 } else {
1269 return $this->getResults();
1270 }
1271 }
1272
1273 public function toLog(AdditionalInformationGenerator $additional_info): array
1274 {
1275 return [
1276 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->getQuestionType(),
1277 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $this->getTitleForHTMLOutput(),
1278 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $this->formatSAQuestion($this->getQuestion()),
1279 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_VARIABLES => $this->buildVariablesForLog(
1280 $this->getVariables(),
1281 $additional_info->getNoneTag()
1282 ),
1283 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_RESULTS => $this->buildResultsForLog(
1284 $this->getResults(),
1285 $additional_info->getNoneTag()
1286 ),
1287 AdditionalInformationGenerator::KEY_FEEDBACK => [
1288 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1289 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1290 ]
1291 ];
1292 }
1293
1298 private function buildVariablesForLog(array $variables, string $none_tag): array
1299 {
1300 return array_reduce(
1301 $variables,
1302 function (array $c, assFormulaQuestionVariable $v) use ($none_tag): array {
1303 $c[$v->getVariable()] = [
1304 AdditionalInformationGenerator::KEY_QUESTION_LOWER_LIMIT => $v->getRangeMinTxt(),
1305 AdditionalInformationGenerator::KEY_QUESTION_UPPER_LIMIT => $v->getRangeMaxTxt(),
1306 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_PRECISION => $v->getPrecision(),
1307 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_INTPRECISION => $v->getIntprecision(),
1308 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_UNIT => $v->getUnit() ?? $none_tag
1309 ];
1310 return $c;
1311 },
1312 []
1313 );
1314 }
1315
1320 private function buildResultsForLog(array $results, string $none_tag): array
1321 {
1322 return array_reduce(
1323 $results,
1324 function (array $c, assFormulaQuestionResult $r) use ($none_tag): array {
1325 $c[$r->getResult()] = [
1326 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_RESULT_TYPE => $r->getResultType(),
1327 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_FORMULA => $r->getFormula(),
1328 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $r->getPoints(),
1329 AdditionalInformationGenerator::KEY_QUESTION_LOWER_LIMIT => $r->getRangeMinTxt(),
1330 AdditionalInformationGenerator::KEY_QUESTION_UPPER_LIMIT => $r->getRangeMaxTxt(),
1331 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_TOLERANCE => $r->getTolerance(),
1332 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_PRECISION => $r->getPrecision(),
1333 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_UNIT => $r->getUnit() ?? $none_tag
1334 ];
1335 return $c;
1336 },
1337 []
1338 );
1339 }
1340
1341 protected function solutionValuesToLog(
1342 AdditionalInformationGenerator $additional_info,
1343 array $solution_values
1344 ): array {
1345 return array_reduce(
1346 $solution_values,
1347 function (array $c, array $v) use ($additional_info): array {
1348 if (str_starts_with($v['value1'], '$v')) {
1349 $var = $this->getVariable($v['value1']);
1350 if ($var === null) {
1351 $c[$v['value1']] = $additional_info->getNoneTag();
1352 return $c;
1353 }
1354 if ($var->getUnit() !== null) {
1355 $c[$v['value1']] = $v['value2'] . $var->getUnit()->getUnit();
1356 return $c;
1357 }
1358 }
1359
1360 if (strpos($v['value1'], '_unit')) {
1361 $unit = $this->getUnitrepository()->getUnit($v['value2']);
1362 $c[$v['value1']] = $unit->getUnit() ?? $additional_info->getNoneTag();
1363 return $c;
1364 }
1365
1366 $c[$v['value1']] = $v['value2'];
1367 return $c;
1368 },
1369 []
1370 );
1371 }
1372
1373 public function solutionValuesToText(array $solution_values): array
1374 {
1375 ksort($solution_values);
1376 return array_reduce(
1377 $solution_values,
1378 function (array $c, array $v): array {
1379 if (!str_starts_with($v['value1'], '$r')) {
1380 return $c;
1381 }
1382 if (!strpos($v['value1'], '_unit')) {
1383 $c[$v['value1']] = "{$v['value1']} = {$v['value2']}";
1384 return $c;
1385 }
1386 $k = substr($v['value1'], 0, -5);
1387 if (array_key_exists($k, $c)) {
1388 $c[$k] .= $v['value2'];
1389 }
1390 return $c;
1391 },
1392 []
1393 );
1394 }
1395
1396 public function getCorrectSolutionForTextOutput(int $active_id, int $pass): array
1397 {
1398 $best_solution = $this->getBestSolution($this->getSolutionValues($active_id, $pass));
1399 return array_map(
1400 function (string $v) use ($best_solution): string {
1401 $solution = "{$v} = {$best_solution[$v]['value']}";
1402 if (isset($best_solution['unit'])) {
1403 $solution .= "{$this->unitrepository->getUnit($best_solution['unit'])->getUnit()}";
1404 }
1405 return $solution;
1406 },
1407 array_keys($best_solution)
1408 );
1409 }
1410
1411 public function getVariablesAsTextArray(int $active_id, int $pass): array
1412 {
1413 $variables = $this->getVariableSolutionValuesForPass($active_id, $pass);
1414 return array_map(
1415 function (string $v) use ($variables): string {
1416 $variable = "{$v} = {$variables[$v]}";
1417 if ($this->getVariable($v)->getUnit() !== null) {
1418 $variable .= $this->getVariable($v)->getUnit()->getUnit();
1419 }
1420 return $variable;
1421 },
1422 array_keys($variables)
1423 );
1424 }
1425}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
Stores random-generated parts of questions in order to present the user with a fixed question during ...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static convertDecimalToCoprimeFraction($decimal_value, $tolerance=1.e-9)
static lookupUnitFactor(int $a_unit_id)
Class for single choice questions assFormulaQuestion is a class for single choice questions.
solutionValuesToText(array $solution_values)
MUST convert the given solution values into text.
toLog(AdditionalInformationGenerator $additional_info)
MUST return an array of the question settings that can be stored in the log.
calculateReachedPoints(int $active_id, ?int $pass=null, bool $authorized_solution=true)
getOperators(string $expression)
Get all available operations for a specific question.
lookupForExistingSolutions(int $active_id, int $pass)
solutionValuesToLog(AdditionalInformationGenerator $additional_info, array $solution_values)
MUST convert the given solution values into an array or a string that can be stored in the log.
addVariable(assFormulaQuestionVariable $variable)
setUnitrepository(\ilUnitConfigurationRepository $unitrepository)
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
ilUnitConfigurationRepository $unitrepository
saveWorkingData(int $active_id, ?int $pass=null, bool $authorized=true)
getUserQuestionResult(int $active_id, int $pass)
Get the user solution for a question by active_id and the test pass.
canUseAdvancedRating($result)
Check if advanced rating can be used for a result.
cloneQuestionTypeSpecificProperties(\assQuestion $target)
getVariable(string $variable)
saveToDb(?int $original_id=null)
getExpressionTypes()
Get all available expression types for a specific question.
hasResultUnit(assFormulaQuestionResult $result, int $unit_id)
addResult(assFormulaQuestionResult $result)
savePreviewData(ilAssQuestionPreviewSession $previewSession)
addResultUnit(?assFormulaQuestionResult $result, ?assFormulaQuestionUnit $unit)
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
buildVariablesForLog(array $variables, string $none_tag)
buildResultsForLog(array $results, string $none_tag)
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
getCorrectSolutionForTextOutput(int $active_id, int $pass)
removeExistingSolutions(int $active_id, int $pass)
addResultUnits(?assFormulaQuestionResult $result, ?array $unit_ids)
__construct(string $title="", string $comment="", string $author="", int $owner=-1, string $question="")
isValidSolutionResultValue(string $submittedValue)
PassPresentedVariablesRepo $pass_presented_variables_repo
getResultUnits(assFormulaQuestionResult $result)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
fetchAllVariables(string $question_text)
hasRequiredVariableSolutionValues(array $userSolution)
getVariablesAsTextArray(int $active_id, int $pass)
generateResultInputHTML(string $result_key, string $result_value, bool $forsolution)
getVariableSolutionValuesForPass(int $active_id, int $pass)
getBestSolution(array $solutions)
substituteVariables(array $userdata, bool $graphicalOutput=false, bool $forsolution=false, bool $result_output=false, array $correctness_icons=[])
isComplete()
Returns true, if the question is complete for use.
static prepareFormOutput($a_str, bool $a_strip=false)
static _div($left_operand, $right_operand, int $scale=50)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static getOperatorsByExpression(string $expression)
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
special template class to simplify handling of ITX/PEAR
Class ilUnitConfigurationRepository.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$c
Definition: deliver.php:25
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$post
Definition: ltitoken.php:46
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
$results
if(!file_exists('../ilias.ini.php'))