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