ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
class.assFormulaQuestion.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
5include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionResult.php";
6include_once "./Modules/TestQuestionPool/classes/class.assFormulaQuestionVariable.php";
7include_once "./Modules/TestQuestionPool/classes/class.ilUnitConfigurationRepository.php";
8include_once "./Modules/Test/classes/inc.AssessmentConstants.php";
9include_once "./Modules/TestQuestionPool/interfaces/interface.iQuestionCondition.php";
10require_once './Modules/TestQuestionPool/classes/class.ilUserQuestionResult.php';
11
20{
21 private $variables;
22 private $results;
23 private $resultunits;
24
29
41 function __construct(
42 $title = "",
43 $comment = "",
44 $author = "",
45 $owner = -1,
46 $question = ""
47 )
48 {
49 parent::__construct($title, $comment, $author, $owner, $question);
50 $this->variables = array();
51 $this->results = array();
52 $this->resultunits = array();
53 $this->unitrepository = new ilUnitConfigurationRepository(0);
54
55 }
56
57 public function clearVariables()
58 {
59 $this->variables = array();
60 }
61
62 public function getVariables()
63 {
64 return $this->variables;
65 }
66
67 public function getVariable($variable)
68 {
69 if(array_key_exists($variable, $this->variables))
70 {
71 return $this->variables[$variable];
72 }
73 return null;
74 }
75
76 public function addVariable($variable)
77 {
78 $this->variables[$variable->getVariable()] = $variable;
79 }
80
81 public function clearResults()
82 {
83 $this->results = array();
84 }
85
86 public function getResults()
87 {
88 return $this->results;
89 }
90
91 public function getResult($result)
92 {
93 if(array_key_exists($result, $this->results))
94 {
95 return $this->results[$result];
96 }
97 return null;
98 }
99
100 public function addResult($result)
101 {
102 $this->results[$result->getResult()] = $result;
103 }
104
105 public function addResultUnits($result, $unit_ids)
106 {
107 $this->resultunits[$result->getResult()] = array();
108 if((!is_object($result)) || (!is_array($unit_ids))) return;
109 foreach($unit_ids as $id)
110 {
111 if(is_numeric($id) && ($id > 0)) $this->resultunits[$result->getResult()][$id] = $this->getUnitrepository()->getUnit($id);
112 }
113 }
114
115 public function addResultUnit($result, $unit)
116 {
117 if(is_object($result) && is_object($unit))
118 {
119 if(!is_array($this->resultunits[$result->getResult()]))
120 {
121 $this->resultunits[$result->getResult()] = array();
122 }
123 $this->resultunits[$result->getResult()][$unit->getId()] = $unit;
124
125 }
126 }
127
128 public function getResultUnits($result)
129 {
130 if(array_key_exists($result->getResult(), $this->resultunits))
131 {
132 return $this->resultunits[$result->getResult()];
133 }
134 else
135 {
136 return array();
137 }
138 }
139
140 public function hasResultUnit($result, $unit_id)
141 {
142 if(array_key_exists($result->getResult(), $this->resultunits))
143 {
144 if(array_key_exists($unit_id, $this->resultunits[$result->getResult()]))
145 {
146 return TRUE;
147 }
148 }
149
150 return FALSE;
151 }
152
153 public function parseQuestionText()
154 {
155 $this->clearResults();
156 $this->clearVariables();
157 if(preg_match_all("/(\\\$v\\d+)/ims", $this->getQuestion(), $matches))
158 {
159 foreach($matches[1] as $variable)
160 {
161 $varObj = new assFormulaQuestionVariable($variable, 0, 0, null, 0);
162 $this->addVariable($varObj);
163 }
164 }
165
166 if(preg_match_all("/(\\\$r\\d+)/ims", $this->getQuestion(), $rmatches))
167 {
168 foreach($rmatches[1] as $result)
169 {
170 $resObj = new assFormulaQuestionResult($result, NULL, NULL, 0, -1, NULL, 1, 1, TRUE);
171 $this->addResult($resObj);
172 }
173 }
174 }
175
177 {
178 if(preg_match_all("/(\\\$v\\d+)/ims", $this->getQuestion(), $matches))
179 {
180 if((count(array_unique($matches[1]))) != count($matches[1])) return false;
181 }
182 return true;
183 }
184
185 public function checkForDuplicateResults()
186 {
187 if(preg_match_all("/(\\\$r\\d+)/ims", $this->getQuestion(), $rmatches))
188 {
189 if((count(array_unique($rmatches[1]))) != count($rmatches[1])) return false;
190 }
191 return true;
192 }
193
194 public function substituteVariables($userdata = null, $graphicalOutput = FALSE, $forsolution = FALSE, $result_output = FALSE, ilAssQuestionPreviewSession $previewSession = null)
195 {
196 global $ilDB;
197
198 if((count($this->results) == 0) && (count($this->variables) == 0))
199 return false;
200
201 $text = $this->getQuestion();
202 if(preg_match_all("/(\\\$r\\d+)/ims", $this->getQuestion(), $rmatches))
203 {
204 foreach($rmatches[1] as $result)
205 {
206 $resObj = $this->getResult($result);
207 $resObj->findValidRandomVariables($this->getVariables(), $this->getResults());
208 }
209 }
210 if(preg_match_all("/(\\\$v\\d+)/ims", $this->getQuestion(), $matches))
211 {
212 foreach($matches[1] as $variable)
213 {
214 $varObj = $this->getVariable($variable);
215 if(is_array($userdata))
216 {
217 if(strlen($userdata[$varObj->getVariable()]))
218 {
219 $value = $userdata[$varObj->getVariable()];
220 $varObj->setValue($value);
221 }
222 elseif( is_object($previewSession) )
223 {
224 $userSolution = $previewSession->getParticipantsSolution();
225 $userSolution[$varObj->getVariable()] = $varObj->getValue();
226 $previewSession->setParticipantsSolution($userSolution);
227 }
228 else
229 {
230 // save value to db
231 $this->saveCurrentSolution($userdata["active_id"], $userdata["pass"], $variable,$varObj->getValue());
232 }
233 }
234 $unit = (is_object($varObj->getUnit())) ? $varObj->getUnit()->getUnit() : "";
235 $val = (strlen($varObj->getValue()) > 8) ? strtoupper(sprintf("%e", $varObj->getValue())) : $varObj->getValue();
236 $text = preg_replace("/\\$" . substr($variable, 1) . "(?![0-9]+)/", $val . " " . $unit . "\\1", $text);
237 }
238 }
239 if(preg_match_all("/(\\\$r\\d+)/ims", $this->getQuestion(), $rmatches))
240 {
241 foreach($rmatches[1] as $result)
242 {
243 $resObj = $this->getResult($result);
244 $value = "";
245 $frac_helper = '';
246 $user_data[$result]['result_type'] = $resObj->getResultType();
247
248 if(
249 $resObj->getResultType() == assFormulaQuestionResult::RESULT_FRAC ||
250 $resObj->getResultType() == assFormulaQuestionResult::RESULT_CO_FRAC
251 )
252 {
253 $is_frac = true;
254 }
255 if(is_array($userdata))
256 {
257 if(is_array($userdata[$result]))
258 {
259 if($forsolution && $result_output)
260 {
261 $value_org = $resObj->calculateFormula($this->getVariables(), $this->getResults(), parent::getId());
262 $value = sprintf("%." . $resObj->getPrecision() . "f", $value_org);
263 if($is_frac)
264 {
266 if(is_array($value))
267 {
268 $frac_helper = $value[1];
269 $value = $value[0];
270 }
271 }
272 }
273 else
274 {
275 if($forsolution)
276 {
277 $value = $userdata[$result]["value"];
278 }
279 else
280 {
281 $value = ' value="' . $userdata[$result]["value"] . '"';
282 }
283 }
284 }
285 }
286 else
287 {
288 if($forsolution)
289 {
290 $value = $resObj->calculateFormula($this->getVariables(), $this->getResults(), parent::getId());
291 $value = sprintf("%." . $resObj->getPrecision() . "f", $value);
292
293 if($is_frac)
294 {
296 if(is_array($value))
297 {
298 $frac_helper = $value[1];
299 $value = $value[0];
300 }
301 $value = ' value="' . $value . '"';
302 }
303 }
304 else
305 {
306 // Precision fix for Preview by tjoussen
307 // If all default values are set, this function is called in getPreview
308 $use_precision = !($userdata == null && $graphicalOutput == FALSE && $forsolution == FALSE && $result_output == FALSE);
309
310 $val = $resObj->calculateFormula($this->getVariables(), $this->getResults(), parent::getId(), $use_precision);
311
312 if($resObj->getResultType() == assFormulaQuestionResult::RESULT_FRAC
313 ||$resObj->getResultType() == assFormulaQuestionResult::RESULT_CO_FRAC)
314 {
315 $val = $resObj->convertDecimalToCoprimeFraction($val);
316 if(is_array($val))
317 {
318 $frac_helper = $val[1];
319 $val = $val[0];
320 }
321 }
322 else
323 {
324 $val = sprintf("%." . $resObj->getPrecision() . "f", $val);
325 $val = (strlen($val) > 8) ? strtoupper(sprintf("%e", $val)) : $val;
326 }
327 $value = ' value="' . $val . '"';
328 }
329 }
330
331 if($forsolution)
332 {
333 $input = '<span class="solutionbox">' . ilUtil::prepareFormOutput($value) . '</span>';
334 }
335 else
336 {
337 $input = '<input type="text" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off" name="result_' . $result . '"' . $value . ' />';
338 }
339
340 $units = "";
341 if(count($this->getResultUnits($resObj)) > 0)
342 {
343 if($forsolution)
344 {
345 if(is_array($userdata))
346 {
347 foreach($this->getResultUnits($resObj) as $unit)
348 {
349 if($userdata[$result]["unit"] == $unit->getId())
350 {
351 $units = $unit->getUnit();
352 }
353 }
354 }
355 else
356 {
357 if($resObj->getUnit())
358 {
359 $units = $resObj->getUnit()->getUnit();
360 }
361 }
362 }
363 else
364 {
365 $units = '<select name="result_' . $result . '_unit">';
366 $units .= '<option value="-1">' . $this->lng->txt("select_unit") . '</option>';
367 foreach($this->getResultUnits($resObj) as $unit)
368 {
369 $units .= '<option value="' . $unit->getId() . '"';
370 if((is_array($userdata[$result])) && (strlen($userdata[$result]["unit"])))
371 {
372 if($userdata[$result]["unit"] == $unit->getId())
373 {
374 $units .= ' selected="selected"';
375 }
376 }
377 $units .= '>' . $unit->getUnit() . '</option>';
378 }
379 $units .= '</select>';
380 }
381 }
382 else
383 {
384 $units = "";
385 }
386 switch($resObj->getResultType())
387 {
389 $units .= ' ' . $this->lng->txt('expected_result_type') . ': ' . $this->lng->txt('result_dec');
390 break;
392 if(strlen($frac_helper))
393 {
394 $units .= ' &asymp; ' . $frac_helper . ', ';
395 }
396 elseif (is_array($userdata) && isset($userdata[$result]) && strlen($userdata[$result]["frac_helper"]))
397 {
398 if(!preg_match('-/-', $value))
399 {
400 $units .= ' &asymp; ' . $userdata[$result]["frac_helper"] . ', ';
401 }
402 }
403 $units .= ' ' . $this->lng->txt('expected_result_type') . ': ' . $this->lng->txt('result_frac');
404 break;
406 if(strlen($frac_helper))
407 {
408 $units .= ' &asymp; ' . $frac_helper . ', ';
409 }
410 elseif (is_array($userdata) && isset($userdata[$result]) && strlen($userdata[$result]["frac_helper"]))
411 {
412 if(!preg_match('-/-', $value))
413 {
414 $units .= ' &asymp; ' . $userdata[$result]["frac_helper"] . ', ';
415 }
416 }
417 $units .= ' ' . $this->lng->txt('expected_result_type') . ': ' . $this->lng->txt('result_co_frac');
418 break;
420 break;
421 }
422 $checkSign = "";
423 if($graphicalOutput)
424 {
425 $resunit = null;
426 $user_value = '';
427 if(is_array($userdata) && is_array($userdata[$result]))
428 {
429 if($userdata[$result]["unit"] > 0)
430 {
431 $resunit = $this->getUnitrepository()->getUnit($userdata[$result]["unit"]);
432 }
433
434 if(isset($userdata[$result]["value"]))
435 {
436 $user_value = $userdata[$result]["value"];
437 }
438 }
439
440 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output_solution_image.html", true, true, 'Modules/TestQuestionPool');
441
442 if($resObj->isCorrect($this->getVariables(), $this->getResults(), $user_value, $resunit))
443 {
444 $template->setCurrentBlock("icon_ok");
445 $template->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
446 $template->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
447 $template->parseCurrentBlock();
448 }
449 else
450 {
451 $template->setCurrentBlock("icon_not_ok");
452 $template->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
453 $template->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
454 $template->parseCurrentBlock();
455 }
456 $checkSign = $template->get();
457 }
458 $resultOutput = "";
459 if($result_output)
460 {
461 $template = new ilTemplate("tpl.il_as_qpl_formulaquestion_output_solution_result.html", true, true, 'Modules/TestQuestionPool');
462
463 if(is_array($userdata))
464 {
465 $found = $resObj->getResultInfo($this->getVariables(), $this->getResults(), $userdata[$resObj->getResult()]["value"], $userdata[$resObj->getResult()]["unit"], $this->getUnitrepository()->getUnits());
466 }
467 else
468 {
469 $found = $resObj->getResultInfo($this->getVariables(), $this->getResults(), $resObj->calculateFormula($this->getVariables(), $this->getResults(), parent::getId()), is_object($resObj->getUnit()) ? $resObj->getUnit()->getId() : NULL, $this->getUnitrepository()->getUnits());
470 }
471 $resulttext = "(";
472 if($resObj->getRatingSimple())
473 {
474 if($frac_helper)
475 {
476 $resulttext .="n/a";
477 }
478 else
479 {
480 $resulttext .= $found['points'] . " " . (($found['points'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points'));
481 }
482 }
483 else
484 {
485 $resulttext .= $this->lng->txt("rated_sign") . " " . (($found['sign']) ? $found['sign'] : 0) . " " . (($found['sign'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points')) . ", ";
486 $resulttext .= $this->lng->txt("rated_value") . " " . (($found['value']) ? $found['value'] : 0) . " " . (($found['value'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points')) . ", ";
487 $resulttext .= $this->lng->txt("rated_unit") . " " . (($found['unit']) ? $found['unit'] : 0) . " " . (($found['unit'] == 1) ? $this->lng->txt('point') : $this->lng->txt('points'));
488 }
489
490 $resulttext .= ")";
491 $template->setVariable("RESULT_OUTPUT", $resulttext);
492
493 $resultOutput = $template->get();
494 }
495 $text = preg_replace("/\\\$" . substr($result, 1) . "(?![0-9]+)/", $input . " " . $units . " " . $checkSign . " " . $resultOutput . " " . "\\1", $text);
496 }
497 }
498 return $text;
499 }
500
508 {
509 $result_units = $this->getResultUnits($result);
510 $resultunit = $result->getUnit();
511 $similar_units = 0;
512 foreach($result_units as $unit)
513 {
514 if(is_object($resultunit))
515 {
516 if($resultunit->getId() != $unit->getId())
517 {
518 if($resultunit->getBaseUnit() && $unit->getBaseUnit())
519 {
520 if($resultunit->getBaseUnit() == $unit->getBaseUnit()) return false;
521 }
522 if($resultunit->getBaseUnit())
523 {
524 if($resultunit->getBaseUnit() == $unit->getId()) return false;
525 }
526 if($unit->getBaseUnit())
527 {
528 if($unit->getBaseUnit() == $resultunit->getId()) return false;
529 }
530 }
531 }
532 }
533 return true;
534 }
535
540 public function isComplete()
541 {
542 if(($this->title) and ($this->author) and ($this->question) and ($this->getMaximumPoints() > 0))
543 {
544 return true;
545 }
546 else
547 {
548 return false;
549 }
550 }
551
556 function saveToDb($original_id = "")
557 {
558 global $ilDB;
559
561 // save variables
562 $affectedRows = $ilDB->manipulateF("
563 DELETE FROM il_qpl_qst_fq_var
564 WHERE question_fi = %s",
565 array("integer"),
566 array($this->getId())
567 );
568
569 $source_qst_id = $original_id;
570 $target_qst_id = $this->getId();
571
572 foreach($this->variables as $variable)
573 {
574 $next_id = $ilDB->nextId('il_qpl_qst_fq_var');
575 $ilDB->insert('il_qpl_qst_fq_var',
576 array(
577 'variable_id' => array('integer', $next_id),
578 'question_fi' => array('integer', $this->getId()),
579 'variable' => array('text', $variable->getVariable()),
580 'range_min' => array('float', ((strlen($variable->getRangeMin())) ? $variable->getRangeMin() : 0.0)),
581 'range_max' => array('float', ((strlen($variable->getRangeMax())) ? $variable->getRangeMax() : 0.0)),
582 'unit_fi' => array('integer', (is_object($variable->getUnit()) ? (int)$variable->getUnit()->getId() : 0)),
583 'varprecision' => array('integer', (int)$variable->getPrecision()),
584 'intprecision' => array('integer', (int)$variable->getIntprecision()),
585 'range_min_txt' => array('text', $variable->getRangeMinTxt()),
586 'range_max_txt' => array('text', $variable->getRangeMaxTxt())
587 ));
588
589 }
590 // save results
591 $affectedRows = $ilDB->manipulateF("DELETE FROM il_qpl_qst_fq_res WHERE question_fi = %s",
592 array("integer"),
593 array($this->getId())
594 );
595
596 foreach($this->results as $result)
597 {
598 $next_id = $ilDB->nextId('il_qpl_qst_fq_res');
599 if( is_object($result->getUnit()))
600 {
601 $tmp_result_unit = $result->getUnit()->getId();
602 }
603 else
604 {
605 $tmp_result_unit = NULL;
606 }
607
608 $formula = str_replace(",", ".", $result->getFormula());
609
610 $ilDB->insert("il_qpl_qst_fq_res", array(
611 "result_id" => array("integer", $next_id),
612 "question_fi" => array("integer", $this->getId()),
613 "result" => array("text", $result->getResult()),
614 "range_min" => array("float", ((strlen($result->getRangeMin())) ? $result->getRangeMin() : 0)),
615 "range_max" => array("float", ((strlen($result->getRangeMax())) ? $result->getRangeMax() : 0)),
616 "tolerance" => array("float", ((strlen($result->getTolerance())) ? $result->getTolerance() : 0)),
617 "unit_fi" => array("integer", (int)$tmp_result_unit),
618 "formula" => array("clob", $formula),
619 "resprecision" => array("integer", $result->getPrecision()),
620 "rating_simple" => array("integer", ($result->getRatingSimple()) ? 1 : 0),
621 "rating_sign" => array("float", ($result->getRatingSimple()) ? 0 : $result->getRatingSign()),
622 "rating_value" => array("float", ($result->getRatingSimple()) ? 0 : $result->getRatingValue()),
623 "rating_unit" => array("float", ($result->getRatingSimple()) ? 0 : $result->getRatingUnit()),
624 "points" => array("float", $result->getPoints()),
625 "result_type" => array('integer', (int)$result->getResultType()),
626 "range_min_txt" => array("text", $result->getRangeMinTxt()),
627 "range_max_txt" => array("text", $result->getRangeMaxTxt())
628
629 ));
630 }
631 // save result units
632 $affectedRows = $ilDB->manipulateF("DELETE FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
633 array("integer"),
634 array($this->getId())
635 );
636 foreach($this->results as $result)
637 {
638 foreach($this->getResultUnits($result) as $unit)
639 {
640 $next_id = $ilDB->nextId('il_qpl_qst_fq_res_unit');
641 $affectedRows = $ilDB->manipulateF("INSERT INTO il_qpl_qst_fq_res_unit (result_unit_id, question_fi, result, unit_fi) VALUES (%s, %s, %s, %s)",
642 array('integer', 'integer', 'text', 'integer'),
643 array(
644 $next_id,
645 $this->getId(),
646 $result->getResult(),
647 $unit->getId()
648 )
649 );
650 }
651 }
652
653
654 // copy category/unit-process:
655 // if $source_qst_id = '' -> nothing to copy because this is a new question
656 // if $source_qst_id == $target_qst_id -> nothing to copy because this is just an update-process
657 // if $source_qst_id != $target_qst_id -> copy categories and untis because this is a copy-process
658 // @todo: Nadia wtf?
659 if($source_qst_id != $target_qst_id && $source_qst_id > 0)
660 {
661 $res = $ilDB->queryF('
662 SELECT * FROM il_qpl_qst_fq_ucat WHERE question_fi = %s',
663 array('integer'), array($source_qst_id));
664
665 $cp_cats = array();
666 while($row = $ilDB->fetchAssoc($res))
667 {
668 $cp_cats[] = $row['category_id'];
669 }
670
671 foreach($cp_cats as $old_category_id)
672 {
673 // copy admin-categorie to custom-category (with question_fi)
674 $new_cat_id = $this->unitrepository->copyCategory($old_category_id, $target_qst_id);
675
676 // copy units to custom_category
677 $this->unitrepository->copyUnitsByCategories($old_category_id, $new_cat_id, $target_qst_id);
678 }
679 }
680 parent::saveToDb();
681 }
682
687 public function loadFromDb($question_id)
688 {
689 global $ilDB;
690
691 $result = $ilDB->queryF("SELECT qpl_questions.* FROM qpl_questions WHERE question_id = %s",
692 array('integer'),
693 array($question_id)
694 );
695 if($result->numRows() == 1)
696 {
697 $data = $ilDB->fetchAssoc($result);
698 $this->setId($question_id);
699 $this->setTitle($data["title"]);
700 $this->setComment($data["description"]);
701 $this->setSuggestedSolution($data["solution_hint"]);
702 $this->setOriginalId($data["original_id"]);
703 $this->setObjId($data["obj_fi"]);
704 $this->setAuthor($data["author"]);
705 $this->setOwner($data["owner"]);
706
707 try
708 {
709 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
710 }
712 {
713 }
714
715 $this->unitrepository = new ilUnitConfigurationRepository($question_id);
716
717 include_once("./Services/RTE/classes/class.ilRTE.php");
718 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
719 $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
720
721 // load variables
722 $result = $ilDB->queryF("SELECT * FROM il_qpl_qst_fq_var WHERE question_fi = %s",
723 array('integer'),
724 array($question_id)
725 );
726 if($result->numRows() > 0)
727 {
728 while($data = $ilDB->fetchAssoc($result))
729 {
730 $varObj = new assFormulaQuestionVariable($data["variable"], $data["range_min"], $data["range_max"], $this->getUnitrepository()->getUnit($data["unit_fi"]), $data["varprecision"], $data["intprecision"]);
731 $varObj->setRangeMinTxt($data['range_min_txt']);
732 $varObj->setRangeMaxTxt($data['range_max_txt']);
733 $this->addVariable($varObj);
734 }
735 }
736 // load results
737 $result = $ilDB->queryF("SELECT * FROM il_qpl_qst_fq_res WHERE question_fi = %s",
738 array('integer'),
739 array($question_id)
740 );
741 if($result->numRows() > 0)
742 {
743 while($data = $ilDB->fetchAssoc($result))
744 {
745 $resObj = new assFormulaQuestionResult($data["result"], $data["range_min"], $data["range_max"], $data["tolerance"], $this->getUnitrepository()->getUnit($data["unit_fi"]), $data["formula"], $data["points"], $data["resprecision"], $data["rating_simple"], $data["rating_sign"], $data["rating_value"], $data["rating_unit"]);
746 $resObj->setResultType($data['result_type']);
747 $resObj->setRangeMinTxt($data['range_min_txt']);
748 $resObj->setRangeMaxTxt($data['range_max_txt']);
749 $this->addResult($resObj);
750 }
751 }
752
753 // load result units
754 $result = $ilDB->queryF("SELECT * FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
755 array('integer'),
756 array($question_id)
757 );
758 if($result->numRows() > 0)
759 {
760 while($data = $ilDB->fetchAssoc($result))
761 {
762 $unit = $this->getUnitrepository()->getUnit($data["unit_fi"]);
763 $resObj = $this->getResult($data["result"]);
764 $this->addResultUnit($resObj, $unit);
765 }
766 }
767 }
768 parent::loadFromDb($question_id);
769 }
770
775 function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
776 {
777 if ($this->id <= 0)
778 {
779 // The question has not been saved. It cannot be duplicated
780 return;
781 }
782 // duplicate the question in database
783 $this_id = $this->getId();
784 $thisObjId = $this->getObjId();
785
786 $clone = $this;
787 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
789 $clone->id = -1;
790
791 if( (int)$testObjId > 0 )
792 {
793 $clone->setObjId($testObjId);
794 }
795
796 if ($title)
797 {
798 $clone->setTitle($title);
799 }
800
801 if ($author)
802 {
803 $clone->setAuthor($author);
804 }
805 if ($owner)
806 {
807 $clone->setOwner($owner);
808 }
809
810 if ($for_test)
811 {
812 $clone->saveToDb($original_id);
813 }
814 else
815 {
816 $clone->saveToDb();
817 }
818
819 // copy question page content
820 $clone->copyPageOfQuestion($this_id);
821 // copy XHTML media objects
822 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
823 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
824
825 return $clone->id;
826 }
827
832 function copyObject($target_questionpool_id, $title = "")
833 {
834 if ($this->id <= 0)
835 {
836 // The question has not been saved. It cannot be duplicated
837 return;
838 }
839 // duplicate the question in database
840 $clone = $this;
841 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
843 $clone->id = -1;
844 $source_questionpool_id = $this->getObjId();
845 $clone->setObjId($target_questionpool_id);
846 if ($title)
847 {
848 $clone->setTitle($title);
849 }
850 $clone->saveToDb();
851 // copy question page content
852 $clone->copyPageOfQuestion($original_id);
853 // copy XHTML media objects
854 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
855
856 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
857
858 return $clone->id;
859 }
860
861 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
862 {
863 if ($this->id <= 0)
864 {
865 // The question has not been saved. It cannot be duplicated
866 return;
867 }
868
869 include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
870
871 $sourceQuestionId = $this->id;
872 $sourceParentId = $this->getObjId();
873
874 // duplicate the question in database
875 $clone = $this;
876 $clone->id = -1;
877
878 $clone->setObjId($targetParentId);
879
880 if ($targetQuestionTitle)
881 {
882 $clone->setTitle($targetQuestionTitle);
883 }
884
885 $clone->saveToDb();
886 // copy question page content
887 $clone->copyPageOfQuestion($sourceQuestionId);
888 // copy XHTML media objects
889 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
890
891 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
892
893 return $clone->id;
894 }
895
900 public function getMaximumPoints()
901 {
902 $points = 0;
903 foreach($this->results as $result)
904 {
905 $points += $result->getPoints();
906 }
907 return $points;
908 }
909
918 function calculateReachedPoints($active_id, $pass = NULL, $returndetails = false)
919 {
920 if(is_null($pass))
921 {
922 $pass = $this->getSolutionMaxPass($active_id);
923 }
924 $solutions =& $this->getSolutionValues($active_id, $pass);
925 $user_solution = array();
926 foreach($solutions as $idx => $solution_value)
927 {
928 if(preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches))
929 {
930 $user_solution[$matches[1]] = $solution_value["value2"];
931 $varObj = $this->getVariable($solution_value["value1"]);
932 $varObj->setValue($solution_value["value2"]);
933 }
934 else if(preg_match("/^(\\\$r\\d+)$/", $solution_value["value1"], $matches))
935 {
936 if(!array_key_exists($matches[1], $user_solution)) $user_solution[$matches[1]] = array();
937 $user_solution[$matches[1]]["value"] = $solution_value["value2"];
938 }
939 else if(preg_match("/^(\\\$r\\d+)_unit$/", $solution_value["value1"], $matches))
940 {
941 if(!array_key_exists($matches[1], $user_solution)) $user_solution[$matches[1]] = array();
942 $user_solution[$matches[1]]["unit"] = $solution_value["value2"];
943 }
944 }
945 //vd($this->getResults());
946 $points = 0;
947 foreach($this->getResults() as $result)
948 {
949 //vd($user_solution[$result->getResult()]["value"]);
950 $points += $result->getReachedPoints($this->getVariables(), $this->getResults(), $user_solution[$result->getResult()]["value"], $user_solution[$result->getResult()]["unit"], $this->unitrepository->getUnits());
951 }
952
953 return $points;
954 }
955
957 {
958 $user_solution = $previewSession->getParticipantsSolution();
959
960 $points = 0;
961 foreach($this->getResults() as $result)
962 {
963 $v = isset($user_solution[$result->getResult()]) ? $user_solution[$result->getResult()] : null;
964 $u = isset($user_solution[$result->getResult().'_unit']) ? $user_solution[$result->getResult().'_unit'] : null;
965
966 $points += $result->getReachedPoints(
967 $this->getVariables(),
968 $this->getResults(),
969 $v,
970 $u,
971 $this->unitrepository->getUnits());
972 }
973
974 return $points;
975 }
976
984 function saveWorkingData($active_id, $pass = NULL)
985 {
986 global $ilDB;
987
988 if(is_null($pass))
989 {
990 include_once "./Modules/Test/classes/class.ilObjTest.php";
991 $pass = ilObjTest::_getPass($active_id);
992 }
993
994 $this->getProcessLocker()->requestUserSolutionUpdateLock();
995
996 $solutionSubmit = $this->getSolutionSubmit();
997
998 $entered_values = FALSE;
999 foreach($solutionSubmit as $key => $value)
1000 {
1001 $matches = null;
1002 if(preg_match("/^result_(\\\$r\\d+)$/", $key, $matches))
1003 {
1004 if(strlen($value)) $entered_values = TRUE;
1005 $result = $ilDB->queryF("SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND " . $ilDB->like('value1', 'clob', $matches[1]),
1006 array('integer', 'integer', 'integer'),
1007 array($active_id, $pass, $this->getId())
1008 );
1009 if($result->numRows())
1010 {
1011 while($row = $ilDB->fetchAssoc($result))
1012 {
1013 $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE solution_id = %s",
1014 array('integer'),
1015 array($row['solution_id'])
1016 );
1017 }
1018 }
1019
1020 $affectedRows = $this->saveCurrentSolution($active_id,$pass,$matches[1],str_replace(",", ".", $value));
1021 }
1022 else if(preg_match("/^result_(\\\$r\\d+)_unit$/", $key, $matches))
1023 {
1024 $result = $ilDB->queryF("SELECT solution_id FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND " . $ilDB->like('value1', 'clob', $matches[1] . "_unit"),
1025 array('integer', 'integer', 'integer'),
1026 array($active_id, $pass, $this->getId())
1027 );
1028 if($result->numRows())
1029 {
1030 while($row = $ilDB->fetchAssoc($result))
1031 {
1032 $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE solution_id = %s",
1033 array('integer'),
1034 array($row['solution_id'])
1035 );
1036 }
1037 }
1038
1039 $affectedRows = $this->saveCurrentSolution($active_id,$pass,$matches[1] . "_unit",$value);
1040 }
1041 }
1042
1043 $this->getProcessLocker()->releaseUserSolutionUpdateLock();
1044
1045 if($entered_values)
1046 {
1047 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1049 {
1050 $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1051 }
1052 }
1053 else
1054 {
1055 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1057 {
1058 $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
1059 }
1060 }
1061
1062 return true;
1063 }
1064
1065 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
1066 {
1067 $userSolution = $previewSession->getParticipantsSolution();
1068
1069 foreach($this->getSolutionSubmit() as $key => $val)
1070 {
1071 $matches = null;
1072
1073 if(preg_match("/^result_(\\\$r\\d+)$/", $key, $matches))
1074 {
1075 $userSolution[$matches[1]] = $val;
1076 }
1077 else if(preg_match("/^result_(\\\$r\\d+)_unit$/", $key, $matches))
1078 {
1079 $userSolution[$matches[1] . "_unit"] = $val;
1080 }
1081 }
1082
1083 $previewSession->setParticipantsSolution($userSolution);
1084 }
1085
1095 protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
1096 {
1097 // nothing to do
1098 }
1099
1104 public function getQuestionType()
1105 {
1106 return "assFormulaQuestion";
1107 }
1108
1113 public function getAdditionalTableName()
1114 {
1115 return "";
1116 }
1117
1122 public function getAnswerTableName()
1123 {
1124 return "";
1125 }
1126
1132 function deleteAnswers($question_id)
1133 {
1134 global $ilDB;
1135
1136 $affectedRows = $ilDB->manipulateF("DELETE FROM il_qpl_qst_fq_var WHERE question_fi = %s",
1137 array('integer'),
1138 array($question_id)
1139 );
1140
1141 $affectedRows = $ilDB->manipulateF("DELETE FROM il_qpl_qst_fq_res WHERE question_fi = %s",
1142 array('integer'),
1143 array($question_id)
1144 );
1145
1146 $affectedRows = $ilDB->manipulateF("DELETE FROM il_qpl_qst_fq_res_unit WHERE question_fi = %s",
1147 array('integer'),
1148 array($question_id)
1149 );
1150 }
1151
1157 {
1158 $text = parent::getRTETextWithMediaObjects();
1159 return $text;
1160 }
1161
1173 public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
1174 {
1175 require_once 'Services/Excel/classes/class.ilExcelUtils.php';
1176 $solution = $this->getSolutionValues($active_id, $pass);
1177 $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
1178 $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
1179 $i = 1;
1180 foreach($solution as $solutionvalue)
1181 {
1182 $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($solutionvalue["value1"]), $format_bold);
1183 if(strpos($solutionvalue["value1"], "_unit"))
1184 {
1185 $unit = $this->getUnitrepository()->getUnit($solutionvalue["value2"]);
1186 if(is_object($unit))
1187 {
1188 $worksheet->write($startrow + $i, 1, $unit->getUnit());
1189 }
1190 }
1191 else
1192 {
1193 $worksheet->write($startrow + $i, 1, $solutionvalue["value2"]);
1194 }
1195 if(preg_match("/(\\\$v\\d+)/", $solutionvalue["value1"], $matches))
1196 {
1197 $var = $this->getVariable($solutionvalue["value1"]);
1198 if(is_object($var) && (is_object($var->getUnit())))
1199 {
1200 $worksheet->write($startrow + $i, 2, $var->getUnit()->getUnit());
1201 }
1202 }
1203 $i++;
1204 }
1205 return $startrow + $i + 1;
1206 }
1207
1213 public function getBestSolution($solutions)
1214 {
1215 $user_solution = array();
1216
1217 foreach($solutions as $idx => $solution_value)
1218 {
1219 if(preg_match("/^(\\\$v\\d+)$/", $solution_value["value1"], $matches))
1220 {
1221 $user_solution[$matches[1]] = $solution_value["value2"];
1222 $varObj = $this->getVariable($matches[1]);
1223 $varObj->setValue($solution_value["value2"]);
1224 }
1225 else if(preg_match("/^(\\\$r\\d+)$/", $solution_value["value1"], $matches))
1226 {
1227 if(!array_key_exists($matches[1], $user_solution)) $user_solution[$matches[1]] = array();
1228 $user_solution[$matches[1]]["value"] = $solution_value["value2"];
1229 }
1230 else if(preg_match("/^(\\\$r\\d+)_unit$/", $solution_value["value1"], $matches))
1231 {
1232 if(!array_key_exists($matches[1], $user_solution)) $user_solution[$matches[1]] = array();
1233 $user_solution[$matches[1]]["unit"] = $solution_value["value2"];
1234 }
1235 }
1236 foreach($this->getResults() as $result)
1237 {
1238 $resVal = $result->calculateFormula($this->getVariables(), $this->getResults(), parent::getId(), false);
1239
1240 if(is_object($result->getUnit()))
1241 {
1242 $user_solution[$result->getResult()]["unit"] = $result->getUnit()->getId();
1243 $user_solution[$result->getResult()]["value"] = $resVal;
1244 }
1245 else if($result->getUnit() == NULL)
1246 {
1247 $unit_factor = 1;
1248 // there is no fix result_unit, any "available unit" is accepted
1249
1250 $available_units = $result->getAvailableResultUnits(parent::getId());
1251 $result_name = $result->getResult();
1252
1253 if($available_units[$result_name] != NULL)
1254 {
1255 $check_unit = in_array($user_solution[$result_name]['unit'], $available_units[$result_name]);
1256 }
1257
1258 if($check_unit == true)
1259 {
1260 //get unit-factor
1261 $unit_factor = assFormulaQuestionUnit::lookupUnitFactor($user_solution[$result_name]['unit']);
1262 $user_solution[$result->getResult()]["value"] = round(ilMath::_div($resVal, $unit_factor), 55);
1263 }
1264 }
1266 || $result->getResultType() == assFormulaQuestionResult::RESULT_FRAC)
1267 {
1269 if(is_array($value))
1270 {
1271 $user_solution[$result->getResult()]["value"] = $value[0];
1272 $user_solution[$result->getResult()]["frac_helper"] = $value[1];
1273 }
1274 else
1275 {
1276 $user_solution[$result->getResult()]["value"] = $value;
1277 $user_solution[$result->getResult()]["frac_helper"] = null;
1278 }
1279 }
1280 elseif($result->getPrecision() > 0)
1281 {
1282 $user_solution[$result->getResult()]["value"] = round($resVal, $result->getPrecision());
1283 }
1284 else
1285 {
1286 $user_solution[$result->getResult()]["value"] = round($resVal);
1287 }
1288 }
1289 return $user_solution;
1290 }
1291
1292 public function setId($id = -1)
1293 {
1294 parent::setId($id);
1295 $this->unitrepository->setConsumerId($this->getId());
1296 }
1297
1301 public function __get($value)
1302 {
1303 switch($value)
1304 {
1305 case "resultunits":
1306 return $this->resultunits;
1307 break;
1308 default:
1309 return parent::__get($value);
1310 break;
1311 }
1312 }
1313
1318 {
1319 $this->unitrepository = $unitrepository;
1320 }
1321
1325 public function getUnitrepository()
1326 {
1327 return $this->unitrepository;
1328 }
1329
1333 protected function getSolutionSubmit()
1334 {
1335 $solutionSubmit = array();
1336 foreach($_POST as $k => $v)
1337 {
1338 if(preg_match("/^result_(\\\$r\\d+)$/", $k))
1339 {
1340 $solutionSubmit[$k] = $v;
1341 } elseif(preg_match("/^result_(\\\$r\\d+)_unit$/", $k))
1342 {
1343 $solutionSubmit[$k] = $v;
1344 }
1345 }
1346 return $solutionSubmit;
1347 }
1348
1357 public function getOperators($expression)
1358 {
1359 require_once "./Modules/TestQuestionPool/classes/class.ilOperatorsExpressionMapping.php";
1361 }
1362
1367 public function getExpressionTypes()
1368 {
1369 return array(
1373 );
1374 }
1375
1384 public function getUserQuestionResult($active_id, $pass)
1385 {
1387 global $ilDB;
1388 $result = new ilUserQuestionResult($this, $active_id, $pass);
1389
1390 $data = $ilDB->queryF(
1391 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = (
1392 SELECT MAX(step) FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s
1393 )",
1394 array("integer", "integer", "integer","integer", "integer", "integer"),
1395 array($active_id, $pass, $this->getId(), $active_id, $pass, $this->getId())
1396 );
1397
1398 while($row = $ilDB->fetchAssoc($data))
1399 {
1400 if(strstr($row["value1"], '$r') && $row["value2"] != null)
1401 {
1402 $result->addKeyValue(str_replace('$r', "", $row["value1"]), $row["value2"]);
1403 }
1404 }
1405
1406 $points = $this->calculateReachedPoints($active_id, $pass);
1407 $max_points = $this->getMaximumPoints();
1408
1409 $result->setReachedPercentage(($points/$max_points) * 100);
1410
1411 return $result;
1412 }
1413
1422 public function getAvailableAnswerOptions($index = null)
1423 {
1424 if($index !== null)
1425 {
1426 return $this->getResult('$r'.($index+1));
1427 }
1428 else
1429 {
1430 return $this->getResults();
1431 }
1432 }
1433}
$result
static convertDecimalToCoprimeFraction($decimal_value, $tolerance=1.e-9)
Class for single choice questions assFormulaQuestion is a class for single choice questions.
getBestSolution($solutions)
Returns the best solution for a given pass of a participant.
getQuestionType()
Returns the question type of the question.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
setUnitrepository($unitrepository)
calculateReachedPoints($active_id, $pass=NULL, $returndetails=false)
Returns the points, a learner has reached answering the question The points are calculated from the g...
canUseAdvancedRating($result)
Check if advanced rating can be used for a result.
hasResultUnit($result, $unit_id)
addResultUnits($result, $unit_ids)
setId($id=-1)
Sets the id of the assQuestion object.
getExpressionTypes()
Get all available expression types for a specific question.
__get($value)
Object getter.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
getOperators($expression)
Get all available operations for a specific question.
reworkWorkingData($active_id, $pass, $obligationsAnswered)
Reworks the allready saved working data if neccessary.
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
copyObject($target_questionpool_id, $title="")
Copies an assFormulaQuestion object @access public.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
Creates an Excel worksheet for the detailed cumulated results of this question.
saveWorkingData($active_id, $pass=NULL)
Saves the learners input of the question to the database.
loadFromDb($question_id)
Loads a assFormulaQuestion object from a database.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assFormulaQuestion @access public.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
saveToDb($original_id="")
Saves a assFormulaQuestion object to a database @access public.
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assFormulaQuestion constructor The constructor takes possible arguments an creates an instance of the...
substituteVariables($userdata=null, $graphicalOutput=FALSE, $forsolution=FALSE, $result_output=FALSE, ilAssQuestionPreviewSession $previewSession=null)
deleteAnswers($question_id)
Deletes datasets from answers tables.
getAnswerTableName()
Returns the name of the answer table in the database.
isComplete()
Returns true, if the question is complete for use.
Abstract basic class which is to be extended by the concrete assessment question type classes.
& getSolutionValues($active_id, $pass=NULL)
Loads solutions of a given user from the database an returns it.
static _getOriginalId($question_id)
Returns the original id of a question.
setOriginalId($original_id)
setObjId($obj_id=0)
Set the object id of the container object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
setSuggestedSolution($solution_id="", $subquestion_index=0, $is_import=false)
Sets a suggested solution for the question.
saveQuestionDataToDb($original_id="")
getId()
Gets the id of the assQuestion object.
getObjId()
Get the object id of the container object.
setTitle($title="")
Sets the title string of the assQuestion object.
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second.
setAuthor($author="")
Sets the authors name of the assQuestion object.
logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
getTitle()
Gets the title string of the assQuestion object.
setComment($comment="")
Sets the comment string of the assQuestion object.
getQuestion()
Gets the question string of the question object.
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
setQuestion($question="")
Sets the question string of the question object.
_convert_text($a_text, $a_target="has been removed")
static _div($left_operand, $right_operand, $scale=50)
_getLogLanguage()
retrieve the log language for assessment logging
_enabledAssessmentLogging()
check wether assessment logging is enabled or not
_getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
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.
Class ilUserQuestionResult.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
static prepareFormOutput($a_str, $a_strip=false)
prepares string output for html forms @access public
$_POST['username']
Definition: cron.php:12
Class iQuestionCondition.
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
global $ilDB