19declare(strict_types=1);
47 $this->variables = [];
49 $this->resultunits = [];
56 $this->variables = [];
66 if (array_key_exists($variable, $this->variables)) {
67 return $this->variables[$variable];
74 $this->variables[$variable->
getVariable()] = $variable;
89 if (array_key_exists($result, $this->results)) {
90 return $this->results[$result];
97 $this->results[$result->
getResult()] = $result;
104 $this->resultunits[$result->
getResult()] = [];
105 if ($result ===
null || $unit_ids ===
null) {
108 foreach ($unit_ids as
$id) {
109 if (is_numeric(
$id) && (
$id > 0)) {
119 if ($result === null || $unit === null) {
123 if (!array_key_exists($result->
getResult(), $this->resultunits) ||
124 !is_array($this->resultunits[$result->
getResult()])) {
125 $this->resultunits[$result->
getResult()] = [];
127 $this->resultunits[$result->
getResult()][$unit->getId()] = $unit;
135 if (!isset($this->resultunits[$result->
getResult()])) {
139 $result_units = $this->resultunits[$result->
getResult()];
144 $a->getSequence() <=>
$b->getSequence()
147 return $result_units;
152 return $this->resultunits;
159 if (array_key_exists($result->getResult(), $this->resultunits)
160 && array_key_exists($unit_id, $this->resultunits[$result->getResult()])) {
169 $this->clearResults();
170 $this->clearVariables();
171 if (preg_match_all(
'/(\$v\d+)/im', $this->getQuestion(), $matches)) {
172 foreach ($matches[1] as $variable) {
174 $this->addVariable($varObj);
178 if (preg_match_all(
'/(\$r\d+)/im', $this->getQuestion(), $rmatches)) {
179 foreach ($rmatches[1] as $result) {
181 $this->addResult($resObj);
188 if (preg_match_all(
'/(\$v\d+)/im', $this->getQuestion(), $matches)) {
189 if ((count(array_unique($matches[1]))) != count($matches[1])) {
198 if (preg_match_all(
'/(\$r\d+)/im', $this->getQuestion(), $rmatches)) {
199 if ((count(array_unique($rmatches[1]))) != count($rmatches[1])) {
215 if (preg_match_all(
'/(\$r\d+)/im', $questionText, $matches)) {
216 foreach ($matches[1] as $resultKey) {
217 $resObjects[] = $this->getResult($resultKey);
232 if (preg_match_all(
'/(\$v\d+)/im', $question_text, $matches)) {
233 $var_objects = array_reduce(
235 function (array
$c,
string $v): array {
236 $vo = $this->getVariable($v);
255 foreach ($this->fetchAllVariables($this->getQuestion()) as $varObj) {
256 if (!isset($userSolution[$varObj->getVariable()])) {
260 if ($userSolution[$varObj->getVariable()] ===
'') {
272 $question_id = $this->
getId();
273 $values = $this->pass_presented_variables_repo->getFor(
278 if (is_null($values)) {
279 $values = $this->getInitialVariableSolutionValues();
280 $this->pass_presented_variables_repo->store(
292 foreach ($this->fetchAllResults($this->getQuestion()) as $resObj) {
293 $resObj->findValidRandomVariables($this->getVariables(), $this->getResults());
296 $variableSolutionValues = [];
298 foreach ($this->fetchAllVariables($this->getQuestion()) as $varObj) {
299 $variableSolutionValues[$varObj->getVariable()] = $varObj->getValue();
302 return $variableSolutionValues;
305 public function saveCurrentSolution(
int $active_id,
int $pass, $value1, $value2,
bool $authorized =
true, $tstamp = 0):
int
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]
314 parent::saveCurrentSolution($active_id, $pass, $val1, $val2, $authorized);
316 return parent::saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized, $tstamp);
324 public function substituteVariables(array $userdata,
bool $graphicalOutput =
false,
bool $forsolution =
false,
bool $result_output =
false, array $correctness_icons = [])
326 if ((count($this->results) == 0) && (count($this->variables) == 0)) {
330 $text = $this->getQuestion();
332 foreach ($this->fetchAllVariables($this->getQuestion()) as $varObj) {
333 if (isset($userdata[$varObj->getVariable()]) && $userdata[$varObj->getVariable()] !==
'') {
334 $varObj->setValue($userdata[$varObj->getVariable()]);
337 $unit = (is_object($varObj->getUnit())) ? $varObj->getUnit()->getUnit() :
"";
340 if ($varObj->getValue() !==
null) {
341 $val = (strlen((
string) $varObj->getValue()) > 8) ? strtoupper(sprintf(
"%e", $varObj->getValue())) : $varObj->getValue();
344 $text = preg_replace(
'/\$' . substr($varObj->getVariable(), 1) .
'(?![0-9]+)/', $val .
' ' . $unit .
'\1',
$text);
347 $text = $this->purifyAndPrepareTextAreaOutput(
$text);
349 if (preg_match_all(
'/(\$r\d+)/im', $this->getQuestion(), $rmatches)) {
350 foreach ($rmatches[1] as $result) {
351 $resObj = $this->getResult($result);
354 $userdata[$result][
'result_type'] = $resObj->getResultType();
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) {
368 if (!is_array($userdata)) {
369 $value = $resObj->calculateFormula($this->getVariables(), $this->getResults(),
parent::getId());
370 $value = sprintf(
"%." . $resObj->getPrecision() .
"f", $value);
375 if (is_array($value)) {
376 $frac_helper = $value[1];
381 $input = $this->generateResultInputHTML($result, $value,
true);
383 $input = $this->generateResultInputHTML($result,
'',
false);
387 $result_units = $this->getResultUnits($resObj);
388 if (count($result_units) > 0) {
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();
396 } elseif ($resObj->getUnit()) {
397 $units = $resObj->getUnit()->getSanitizedUnit();
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"';
411 $units .=
'>' . $unit->getSanitizedUnit() .
'</option>';
413 $units .=
'</select>';
418 switch ($resObj->getResultType()) {
420 $units .=
' ' . $this->
lng->txt(
'expected_result_type') .
': ' . $this->
lng->txt(
'result_dec');
423 if ($frac_helper !==
'') {
424 $units .=
' ≈ ' . $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 .=
' ≈ ' . $userdata[$result][
"frac_helper"] .
', ';
433 $units .=
' ' . $this->
lng->txt(
'expected_result_type') .
': ' . $this->
lng->txt(
'result_frac');
436 if ($frac_helper !==
'') {
437 $units .=
' ≈ ' . $frac_helper .
', ';
438 } elseif (isset($userdata[$result][
"frac_helper"]) && is_array($userdata) && $userdata[$result][
"frac_helper"] !==
'') {
439 if (!str_contains($value,
'/')) {
440 $units .=
' ≈ ' . $userdata[$result][
"frac_helper"] .
', ';
443 $units .=
' ' . $this->
lng->txt(
'expected_result_type') .
': ' . $this->
lng->txt(
'result_co_frac');
449 if ($graphicalOutput) {
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"]);
457 if (isset($userdata[$result][
"value"])) {
458 $user_value = $userdata[$result][
"value"];
462 $template =
new ilTemplate(
"tpl.il_as_qpl_formulaquestion_output_solution_image.html",
true,
true,
'components/ILIAS/TestQuestionPool');
464 $correctness_icon = $correctness_icons[
'not_correct'];
465 if ($resObj->isCorrect($this->getVariables(), $this->getResults(), $user_value, $resunit)) {
466 $correctness_icon = $correctness_icons[
'correct'];
468 $template->setCurrentBlock(
"icon_ok");
469 $template->setVariable(
"ICON_OK", $correctness_icon);
470 $template->parseCurrentBlock();
472 $checkSign = $template->get();
475 if ($result_output) {
476 $template =
new ilTemplate(
"tpl.il_as_qpl_formulaquestion_output_solution_result.html",
true,
true,
'components/ILIAS/TestQuestionPool');
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(),
484 $userdata[$resObj->getResult()][
"value"],
485 $userdata[$resObj->getResult()][
"unit"] ??
null,
486 $this->getUnitrepository()->getUnits()
489 $found = $resObj->getResultInfo(
490 $this->getVariables(),
492 $resObj->calculateFormula($this->getVariables(), $this->getResults(),
parent::getId()),
493 is_object($resObj->getUnit()) ? $resObj->getUnit()->getId() :
null,
494 $this->getUnitrepository()->getUnits()
498 if ($resObj->getRatingSimple()) {
500 $resulttext .=
"n/a";
502 $resulttext .= $found[
'points'] .
" " . (($found[
'points'] == 1) ? $this->
lng->txt(
'point') : $this->
lng->txt(
'points'));
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'));
511 $template->setVariable(
"RESULT_OUTPUT", $resulttext);
513 $resultOutput = $template->get();
515 $text = preg_replace(
'/\$' . substr($result, 1) .
'(?![0-9]+)/', $input .
' ' . $units .
' ' . $checkSign .
' ' . $resultOutput .
' ' .
'\1',
$text);
524 return '<span class="ilc_qinput_TextInput solutionbox">'
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 .
'"/>';
543 $result_units = $this->getResultUnits($result);
544 $resultunit = $result->
getUnit();
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()) {
554 if ($resultunit->getBaseUnit()) {
555 if ($resultunit->getBaseUnit() == $unit->getId()) {
559 if ($unit->getBaseUnit()) {
560 if ($unit->getBaseUnit() == $resultunit->getId()) {
576 if (($this->title) and ($this->author) and ($this->question) and ($this->getMaximumPoints() > 0)) {
583 public function saveToDb(?
int $original_id =
null): void
585 $this->saveQuestionDataToDb($original_id);
587 $affectedRows = $this->db->manipulateF(
589 DELETE FROM il_qpl_qst_fq_var
590 WHERE question_fi = %s",
595 foreach ($this->variables as $variable) {
596 $next_id = $this->db->nextId(
'il_qpl_qst_fq_var');
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()]
614 $affectedRows = $this->db->manipulateF(
615 "DELETE FROM il_qpl_qst_fq_res WHERE question_fi = %s",
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();
625 $tmp_result_unit =
null;
629 if ($result->getFormula() !==
null) {
630 $formula = str_replace(
",",
".", $result->getFormula());
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()]
655 $affectedRows = $this->db->manipulateF(
656 "DELETE FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
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'],
669 $result->getResult(),
681 $result = $this->db->queryF(
682 "SELECT qpl_questions.* FROM qpl_questions WHERE question_id = %s",
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"]);
704 $this->setAdditionalContentEditingMode(
$data[
'add_cont_edit_mode']);
713 $result = $this->db->queryF(
714 "SELECT * FROM il_qpl_qst_fq_var WHERE question_fi = %s",
718 if ($result->numRows() > 0) {
719 while (
$data = $this->db->fetchAssoc($result)) {
722 $data[
'range_min_txt'],
723 $data[
'range_max_txt'],
724 $this->getUnitrepository()->getUnit(
$data[
'unit_fi']),
725 $data[
'varprecision'],
726 $data[
'intprecision']
728 $this->addVariable($varObj);
732 $result = $this->db->queryF(
733 "SELECT * FROM il_qpl_qst_fq_res WHERE question_fi = %s",
737 if ($result->numRows() > 0) {
738 while (
$data = $this->db->fetchAssoc($result)) {
741 $data[
'range_min_txt'],
742 $data[
'range_max_txt'],
744 $this->getUnitrepository()->getUnit(
$data[
'unit_fi']),
747 $data[
'resprecision'],
748 $data[
'rating_simple'] === 1,
749 $data[
'rating_sign'],
750 $data[
'rating_value'],
753 $resObj->setResultType(
$data[
'result_type']);
754 $this->addResult($resObj);
759 $result = $this->db->queryF(
760 "SELECT * FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
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);
772 parent::loadFromDb($question_id);
778 $this->unitrepository->cloneUnits($this->
getId(), $target->
getId());
789 foreach ($this->results as $result) {
790 $points += $result->getPoints();
798 bool $authorized_solution =
true
800 if ($pass === null) {
801 $pass = $this->getSolutionMaxPass($active_id);
803 $solutions = $this->getSolutionValues($active_id, $pass, $authorized_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']);
813 if (preg_match(
'/^(\$r\d+)$/', $solution_value[
'value1'], $matches)) {
814 if (!array_key_exists($matches[1], $user_solution)) {
815 $user_solution[$matches[1]] = [];
817 $user_solution[$matches[1]][
'value'] = $solution_value[
'value2'];
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]] = [];
825 $user_solution[$matches[1]][
'unit'] = $this->unitrepository->getUnit(
826 $this->
refinery->kindlyTo()->int()->transform($solution_value[
'value2']),
832 foreach ($this->getResults() as $result) {
833 $points += $result->getReachedPoints(
834 $this->getVariables(),
836 $user_solution[$result->getResult()][
'value'] ??
'',
837 $user_solution[$result->getResult()][
'unit'] ??
null,
838 $this->unitrepository->getUnits()
842 return (
float) $points;
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]
856 $points += $result->getReachedPoints(
857 $this->getVariables(),
859 $user_solution[$result->getResult()] ??
'',
860 $unit_id !==
null ? $this->unitrepository->getUnit($unit_id) :
null,
861 $this->unitrepository->getUnits()
864 return $this->ensureNonNegativePoints($points);
869 $submittedValue = str_replace(
',',
'.', $submittedValue);
871 if (is_numeric($submittedValue)) {
875 if (preg_match(
'/^[-+]?\d+\/\d+$/', $submittedValue)) {
885 bool $authorized =
true
887 if (is_null($pass)) {
891 $answer = $this->getSolutionSubmit();
892 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
893 function () use ($answer, $active_id, $pass, $authorized) {
894 foreach ($answer as $key => $value) {
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]);
899 if ($this->getStep() !==
null) {
900 $queryResult .=
" AND step = " . $this->db->quote((
int) $this->getStep(),
'integer') .
" ";
903 $result = $this->db->queryF(
905 [
'integer',
'integer',
'integer',
'integer'],
906 [$active_id, $pass, $this->
getId(), (
int) $authorized]
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]
918 $this->saveCurrentSolution($active_id, $pass, $matches[1], str_replace(
",",
".", $value), $authorized);
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");
925 if ($this->getStep() !==
null) {
926 $queryResultUnit .=
" AND step = " . $this->db->quote((
int) $this->getStep(),
'integer') .
" ";
929 $result = $this->db->queryF(
931 [
'integer',
'integer',
'integer',
'integer'],
932 [$active_id, $pass, $this->
getId(), (
int) $authorized]
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]
944 $this->saveCurrentSolution($active_id, $pass, $matches[1] .
"_unit", $value, $authorized);
959 'authorized' =>
false,
960 'intermediate' => false
964 SELECT authorized, COUNT(*) cnt
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
974 if ($this->getStep() !==
null) {
975 $query .=
" AND step = " . $this->db->quote((
int) $this->getStep(),
'integer') .
" ";
982 $result = $this->db->query($query);
984 while ($row = $this->db->fetchAssoc($result)) {
985 if ($row[
'authorized']) {
986 $return[
'authorized'] = $row[
'cnt'] > 0;
988 $return[
'intermediate'] = $row[
'cnt'] > 0;
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%'
1004 if ($this->getStep() !==
null) {
1005 $query .=
" AND step = " . $this->db->quote((
int) $this->getStep(),
'integer') .
" ";
1008 return $this->db->manipulate($query);
1015 foreach ($this->getSolutionSubmit() as $key => $val) {
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;
1030 return "assFormulaQuestion";
1045 $affectedRows = $this->db->manipulateF(
1046 "DELETE FROM il_qpl_qst_fq_var WHERE question_fi = %s",
1051 $affectedRows = $this->db->manipulateF(
1052 "DELETE FROM il_qpl_qst_fq_res WHERE question_fi = %s",
1057 $affectedRows = $this->db->manipulateF(
1058 "DELETE FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
1063 $affectedRows = $this->db->manipulateF(
1064 "DELETE FROM il_qpl_qst_fq_ucat WHERE question_fi = %s",
1069 $affectedRows = $this->db->manipulateF(
1070 "DELETE FROM il_qpl_qst_fq_unit WHERE question_fi = %s",
1078 $text = parent::getRTETextWithMediaObjects();
1084 $user_solution = [];
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]] = [];
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]] = [];
1100 $user_solution[$matches[1]][
'unit'] = $solution_value[
'value2'];
1103 foreach ($this->getResults() as $result) {
1104 $resVal = $result->calculateFormula($this->getVariables(), $this->getResults(), $this->
getId(),
false);
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) {
1113 $available_units = $result->getAvailableResultUnits(
parent::getId());
1114 $result_name = $result->getResult();
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]);
1122 if ($check_unit ==
true) {
1128 $user_solution[$result->getResult()][
'value'] =
ilMath::_div($resVal, $unit_factor, 55);
1130 $user_solution[$result->getResult()][
'value'] = 0;
1136 if (is_array($value)) {
1137 $user_solution[$result->getResult()][
'value'] = $value[0];
1138 $user_solution[$result->getResult()][
'frac_helper'] = $value[1];
1140 $user_solution[$result->getResult()][
'value'] = $value;
1141 $user_solution[$result->getResult()][
'frac_helper'] =
null;
1144 $user_solution[$result->getResult()][
'value'] = round((
float) $user_solution[$result->getResult()][
'value'], $result->getPrecision());
1147 return $user_solution;
1153 $this->unitrepository->setConsumerId($this->
getId());
1158 $this->unitrepository = $unitrepository;
1163 return $this->unitrepository;
1171 $solutionSubmit = [];
1173 $post = $this->dic->http()->wrapper()->post();
1175 foreach ($this->getResults() as $index =>
$a) {
1176 $key =
"result_$index";
1177 if (
$post->has($key)) {
1178 $value =
$post->retrieve(
1180 $this->dic->refinery()->kindlyTo()->string()
1183 $solutionSubmit[$key] = $value;
1185 if (
$post->has($key .
"_unit")) {
1186 $value =
$post->retrieve(
1188 $this->dic->refinery()->kindlyTo()->string()
1190 $solutionSubmit[$key .
"_unit"] = $value;
1193 return $solutionSubmit;
1198 foreach ($this->getSolutionSubmit() as $value) {
1199 if ($value && !$this->isValidSolutionResultValue($value)) {
1200 $this->tpl->setOnScreenMessage(
1202 $this->
lng->txt(
"err_no_numeric_value"),
1232 $maxStep = $this->lookupMaxStep($active_id, $pass);
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]
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()]
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']);
1253 $points = $this->calculateReachedPoints($active_id, $pass);
1254 $max_points = $this->getMaximumPoints();
1256 $result->setReachedPercentage(($points / $max_points) * 100);
1271 if ($index !==
null) {
1272 return $this->getResult(
'$r' . ($index + 1));
1274 return $this->getResults();
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(),
1288 AdditionalInformationGenerator::KEY_QUESTION_FORMULA_RESULTS => $this->buildResultsForLog(
1289 $this->getResults(),
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))
1305 return array_reduce(
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
1327 return array_reduce(
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
1348 array $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) {
1359 if ($var->getUnit() !==
null) {
1360 $c[$v[
'value1']] = $v[
'value2'] . $var->getUnit()->getUnit();
1365 if (strpos($v[
'value1'],
'_unit')) {
1366 $unit = $this->getUnitrepository()->getUnit($v[
'value2']);
1367 $c[$v[
'value1']] = $unit->getUnit() ?? $additional_info->getNoneTag();
1371 $c[$v[
'value1']] = $v[
'value2'];
1380 ksort($solution_values);
1381 return array_reduce(
1383 function (array
$c, array $v): array {
1384 if (!str_starts_with($v[
'value1'],
'$r')) {
1387 if (!strpos($v[
'value1'],
'_unit')) {
1388 $c[$v[
'value1']] =
"{$v['value1']} = {$v['value2']}";
1391 $k = substr($v[
'value1'], 0, -5);
1392 if (array_key_exists($k,
$c)) {
1393 $c[$k] .= $v[
'value2'];
1403 $best_solution = $this->getBestSolution($this->getSolutionValues($active_id, $pass));
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()}";
1412 array_keys($best_solution)
1418 $variables = $this->getVariableSolutionValuesForPass($active_id, $pass);
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();
1427 array_keys($variables)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Stores random-generated parts of questions in order to present the user with a fixed question during ...
static getDraftInstance()
static getInstance($identifier)
getParticipantsSolution()
setParticipantsSolution($participantSolution)
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...
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...
const PercentageResultExpression
const NumericResultExpression
const EmptyAnswerExpression
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
if(!file_exists('../ilias.ini.php'))