ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.assNumericGUI.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once './Modules/TestQuestionPool/classes/class.assQuestionGUI.php';
5 require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiQuestionScoringAdjustable.php';
6 require_once './Modules/TestQuestionPool/interfaces/interface.ilGuiAnswerScoringAdjustable.php';
7 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
8 
26 {
36  public function __construct($id = -1)
37  {
38  parent::__construct();
39  require_once './Modules/TestQuestionPool/classes/class.assNumeric.php';
40  $this->object = new assNumeric();
41  if ($id >= 0) {
42  $this->object->loadFromDb($id);
43  }
44  }
45 
46  public function getCommand($cmd)
47  {
48  if (substr($cmd, 0, 6) == "delete") {
49  $cmd = "delete";
50  }
51  return $cmd;
52  }
53 
57  protected function writePostData($always = false)
58  {
59  $hasErrors = (!$always) ? $this->editQuestion(true) : false;
60  if (!$hasErrors) {
61  require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
65  $this->saveTaxonomyAssignments();
66  return 0;
67  }
68  return 1;
69  }
70 
78  public function editQuestion($checkonly = false)
79  {
80  $save = $this->isSaveCommand();
81  $this->getQuestionTemplate();
82 
83  include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
84  $form = new ilPropertyFormGUI();
85  $this->editForm = $form;
86 
87  $form->setFormAction($this->ctrl->getFormAction($this));
88  $form->setTitle($this->outQuestionType());
89  $form->setMultipart(true);
90  $form->setTableWidth("100%");
91  $form->setId("assnumeric");
92 
98 
99  $errors = false;
100 
101  if ($save) {
102  $form->setValuesByPost();
103  $errors = !$form->checkInput();
104  $form->setValuesByPost(); // again, because checkInput now performs the whole stripSlashes handling and we need this if we don't want to have duplication of backslashes
105 
106  $lower = $form->getItemByPostVar('lowerlimit');
107  $upper = $form->getItemByPostVar('upperlimit');
108 
109  if (!$this->checkRange($lower->getValue(), $upper->getValue())) {
110  global $DIC;
111  $lower->setAlert($DIC->language()->txt('qpl_numeric_lower_needs_valid_lower_alert'));
112  $upper->setAlert($DIC->language()->txt('qpl_numeric_upper_needs_valid_upper_alert'));
113  ilUtil::sendFailure($DIC->language()->txt("form_input_not_valid"));
114  $errors = true;
115  }
116 
117  if ($errors) {
118  $checkonly = false;
119  }
120  }
121 
122  if (!$checkonly) {
123  $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
124  }
125  return $errors;
126  }
127 
135  public function checkRange($lower, $upper)
136  {
137  include_once "./Services/Math/classes/class.EvalMath.php";
138  $eval = new EvalMath();
139  $eval->suppress_errors = true;
140  if (($eval->e($lower) !== false) and ($eval->e($upper) !== false)) {
141  if ($eval->e($lower) <= $eval->e($upper)) {
142  return true;
143  } else {
144  return false;
145  }
146  }
147  return false;
148  }
149 
156  {
157  return true;
158  }
159 
175  public function getSolutionOutput(
176  $active_id,
177  $pass = null,
178  $graphicalOutput = false,
179  $result_output = false,
180  $show_question_only = true,
181  $show_feedback = false,
182  $show_correct_solution = false,
183  $show_manual_scoring = false,
184  $show_question_text = true
185  ) {
186  // get the solution of the user for the active pass or from the last pass if allowed
187  $solutions = array();
188  if (($active_id > 0) && (!$show_correct_solution)) {
189  $solutions = $this->object->getSolutionValues($active_id, $pass, !$this->getUseIntermediateSolution());
190  } else {
191  array_push($solutions, array("value1" => sprintf($this->lng->txt("value_between_x_and_y"), $this->object->getLowerLimit(), $this->object->getUpperLimit())));
192  }
193 
194  // generate the question output
195  require_once './Services/UICore/classes/class.ilTemplate.php';
196  $template = new ilTemplate("tpl.il_as_qpl_numeric_output_solution.html", true, true, "Modules/TestQuestionPool");
197  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
198  if (is_array($solutions)) {
199  if (($active_id > 0) && (!$show_correct_solution)) {
200  if ($graphicalOutput) {
201  if ($this->object->getStep() === null) {
202  $reached_points = $this->object->getReachedPoints($active_id, $pass);
203  } else {
204  $reached_points = $this->object->calculateReachedPoints($active_id, $pass);
205  }
206  // output of ok/not ok icons for user entered solutions
207  if ($reached_points == $this->object->getMaximumPoints()) {
208  $template->setCurrentBlock("icon_ok");
209  $template->setVariable("ICON_OK", ilUtil::getImagePath("icon_ok.svg"));
210  $template->setVariable("TEXT_OK", $this->lng->txt("answer_is_right"));
211  $template->parseCurrentBlock();
212  } else {
213  $template->setCurrentBlock("icon_ok");
214  $template->setVariable("ICON_NOT_OK", ilUtil::getImagePath("icon_not_ok.svg"));
215  $template->setVariable("TEXT_NOT_OK", $this->lng->txt("answer_is_wrong"));
216  $template->parseCurrentBlock();
217  }
218  }
219  }
220  foreach ($solutions as $solution) {
221  $template->setVariable("NUMERIC_VALUE", $solution["value1"]);
222  }
223  if (count($solutions) == 0) {
224  $template->setVariable("NUMERIC_VALUE", "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
225  }
226  }
227  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
228  $questiontext = $this->object->getQuestion();
229  if ($show_question_text == true) {
230  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
231  }
232  $questionoutput = $template->get();
233  //$feedback = ($show_feedback) ? $this->getAnswerFeedbackOutput($active_id, $pass) : ""; // Moving new method
234  // due to deprecation.
235  $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput($active_id, $pass) : "";
236  if (strlen($feedback)) {
237  $cssClass = (
238  $this->hasCorrectSolution($active_id, $pass) ?
240  );
241 
242  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
243  $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
244  }
245  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
246 
247  $solutionoutput = $solutiontemplate->get();
248  if (!$show_question_only) {
249  // get page object output
250  $solutionoutput = $this->getILIASPage($solutionoutput);
251  }
252  return $solutionoutput;
253  }
254 
260  public function getPreview($show_question_only = false, $showInlineFeedback = false)
261  {
262  // generate the question output
263  require_once './Services/UICore/classes/class.ilTemplate.php';
264  $template = new ilTemplate("tpl.il_as_qpl_numeric_output.html", true, true, "Modules/TestQuestionPool");
265  if (is_object($this->getPreviewSession())) {
266  $template->setVariable("NUMERIC_VALUE", " value=\"" . $this->getPreviewSession()->getParticipantsSolution() . "\"");
267  }
268  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
269  $questiontext = $this->object->getQuestion();
270  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
271  $questionoutput = $template->get();
272  if (!$show_question_only) {
273  // get page object output
274  $questionoutput = $this->getILIASPage($questionoutput);
275  }
276  return $questionoutput;
277  }
278 
287  // hey: prevPassSolutions - pass will be always available from now on
288  public function getTestOutput($active_id, $pass, $is_postponed = false, $use_post_solutions = false, $inlineFeedback)
289  // hey.
290  {
291  $solutions = null;
292  // get the solution of the user for the active pass or from the last pass if allowed
293  if ($use_post_solutions !== false) {
294  $solutions = array(
295  array('value1' => $use_post_solutions['numeric_result'])
296  );
297  } elseif ($active_id) {
298 
299  // hey: prevPassSolutions - obsolete due to central check
300  #include_once "./Modules/Test/classes/class.ilObjTest.php";
301  #if (!ilObjTest::_getUsePreviousAnswers($active_id, true))
302  #{
303  # if (is_null($pass)) $pass = ilObjTest::_getPass($active_id);
304  #}
305  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
306  // hey.
307  }
308 
309  // generate the question output
310  require_once './Services/UICore/classes/class.ilTemplate.php';
311  $template = new ilTemplate("tpl.il_as_qpl_numeric_output.html", true, true, "Modules/TestQuestionPool");
312  if (is_array($solutions)) {
313  foreach ($solutions as $solution) {
314  $template->setVariable("NUMERIC_VALUE", " value=\"" . $solution["value1"] . "\"");
315  }
316  }
317  $template->setVariable("NUMERIC_SIZE", $this->object->getMaxChars());
318  $questiontext = $this->object->getQuestion();
319  $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
320  $questionoutput = $template->get();
321  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
322  return $pageoutput;
323  }
324 
330  public function setQuestionTabs()
331  {
334  global $DIC;
335  $rbacsystem = $DIC['rbacsystem'];
336  $ilTabs = $DIC['ilTabs'];
337 
338  $ilTabs->clearTargets();
339 
340  $this->ctrl->setParameterByClass("ilAssQuestionPageGUI", "q_id", $_GET["q_id"]);
341  include_once "./Modules/TestQuestionPool/classes/class.assQuestion.php";
342  $q_type = $this->object->getQuestionType();
343 
344  if (strlen($q_type)) {
345  $classname = $q_type . "GUI";
346  $this->ctrl->setParameterByClass(strtolower($classname), "sel_question_types", $q_type);
347  $this->ctrl->setParameterByClass(strtolower($classname), "q_id", $_GET["q_id"]);
348  }
349 
350  if ($_GET["q_id"]) {
351  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
352  // edit page
353  $ilTabs->addTarget(
354  "edit_page",
355  $this->ctrl->getLinkTargetByClass("ilAssQuestionPageGUI", "edit"),
356  array("edit", "insert", "exec_pg"),
357  "",
358  "",
359  $force_active
360  );
361  }
362 
363  $this->addTab_QuestionPreview($ilTabs);
364  }
365 
366  $force_active = false;
367  if ($rbacsystem->checkAccess('write', $_GET["ref_id"])) {
368  $url = "";
369  if ($classname) {
370  $url = $this->ctrl->getLinkTargetByClass($classname, "editQuestion");
371  }
372  // edit question properties
373  $ilTabs->addTarget(
374  "edit_question",
375  $url,
376  array("editQuestion", "save", "cancel", "saveEdit", "originalSyncForm"),
377  $classname,
378  "",
379  $force_active
380  );
381  }
382 
383  // add tab for question feedback within common class assQuestionGUI
384  $this->addTab_QuestionFeedback($ilTabs);
385 
386  // add tab for question hint within common class assQuestionGUI
387  $this->addTab_QuestionHints($ilTabs);
388 
389  // add tab for question's suggested solution within common class assQuestionGUI
390  $this->addTab_SuggestedSolution($ilTabs, $classname);
391 
392  // Assessment of questions sub menu entry
393  if ($_GET["q_id"]) {
394  $ilTabs->addTarget(
395  "statistics",
396  $this->ctrl->getLinkTargetByClass($classname, "assessment"),
397  array("assessment"),
398  $classname,
399  ""
400  );
401  }
402 
403  $this->addBackTab($ilTabs);
404  }
405 
412  public function getSpecificFeedbackOutput($userSolution)
413  {
414  $output = "";
415  return $this->object->prepareTextareaOutput($output, true);
416  }
417 
419  {
420  $this->object->setMaxChars($_POST["maxchars"]);
421  }
422 
424  {
425  $this->object->setLowerLimit($_POST['lowerlimit']);
426  $this->object->setUpperLimit($_POST['upperlimit']);
427  $this->object->setPoints($_POST['points']);
428  }
429 
431  {
432  // maxchars
433  $maxchars = new ilNumberInputGUI($this->lng->txt("maxchars"), "maxchars");
434  $maxchars->setInfo($this->lng->txt('qpl_maxchars_info_numeric_question'));
435  $maxchars->setSize(10);
436  $maxchars->setDecimals(0);
437  $maxchars->setMinValue(1);
438  $maxchars->setRequired(true);
439  if ($this->object->getMaxChars() > 0) {
440  $maxchars->setValue($this->object->getMaxChars());
441  }
442  $form->addItem($maxchars);
443  }
444 
446  {
447  // points
448  $points = new ilNumberInputGUI($this->lng->txt("points"), "points");
449  $points->allowDecimals(true);
450  $points->setValue($this->object->getPoints() > 0 ? $this->object->getPoints() : '');
451  $points->setRequired(true);
452  $points->setSize(3);
453  $points->setMinValue(0.0);
454  $points->setMinvalueShouldBeGreater(true);
455  $form->addItem($points);
456 
458  $header->setTitle($this->lng->txt("range"));
459  $form->addItem($header);
460 
461  // lower bound
462  $lower_limit = new ilFormulaInputGUI($this->lng->txt("range_lower_limit"), "lowerlimit");
463  $lower_limit->setSize(25);
464  $lower_limit->setMaxLength(20);
465  $lower_limit->setRequired(true);
466  $lower_limit->setValue($this->object->getLowerLimit());
467  $form->addItem($lower_limit);
468 
469  // upper bound
470  $upper_limit = new ilFormulaInputGUI($this->lng->txt("range_upper_limit"), "upperlimit");
471  $upper_limit->setSize(25);
472  $upper_limit->setMaxLength(20);
473  $upper_limit->setRequired(true);
474  $upper_limit->setValue($this->object->getUpperLimit());
475  $form->addItem($upper_limit);
476 
477  // reset input length, if max chars are set
478  if ($this->object->getMaxChars() > 0) {
479  $lower_limit->setSize($this->object->getMaxChars());
480  $lower_limit->setMaxLength($this->object->getMaxChars());
481  $upper_limit->setSize($this->object->getMaxChars());
482  $upper_limit->setMaxLength($this->object->getMaxChars());
483  }
484  }
485 
496  {
497  return array();
498  }
499 
510  {
511  return array();
512  }
513 
522  public function getAggregatedAnswersView($relevant_answers)
523  {
524  return $this->renderAggregateView(
525  $this->aggregateAnswers($relevant_answers)
526  )->get();
527  }
528 
529  public function aggregateAnswers($relevant_answers_chosen)
530  {
531  $aggregate = array();
532 
533  foreach ($relevant_answers_chosen as $relevant_answer) {
534  if (array_key_exists($relevant_answer['value1'], $aggregate)) {
535  $aggregate[$relevant_answer['value1']]++;
536  } else {
537  $aggregate[$relevant_answer['value1']] = 1;
538  }
539  }
540  return $aggregate;
541  }
542 
548  public function renderAggregateView($aggregate)
549  {
550  $tpl = new ilTemplate('tpl.il_as_aggregated_answers_table.html', true, true, "Modules/TestQuestionPool");
551 
552  $tpl->setCurrentBlock('headercell');
553  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_answer_header'));
554  $tpl->parseCurrentBlock();
555 
556  $tpl->setCurrentBlock('headercell');
557  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_frequency_header'));
558  $tpl->parseCurrentBlock();
559 
560  foreach ($aggregate as $key => $value) {
561  $tpl->setCurrentBlock('aggregaterow');
562  $tpl->setVariable('OPTION', $key);
563  $tpl->setVariable('COUNT', $value);
564  $tpl->parseCurrentBlock();
565  }
566  return $tpl;
567  }
568 
569  public function getAnswersFrequency($relevantAnswers, $questionIndex)
570  {
571  $answers = array();
572 
573  foreach ($relevantAnswers as $ans) {
574  if (!isset($answers[$ans['value1']])) {
575  $answers[$ans['value1']] = array(
576  'answer' => $ans['value1'], 'frequency' => 0
577  );
578  }
579 
580  $answers[$ans['value1']]['frequency']++;
581  }
582 
583  return $answers;
584  }
585 
587  {
588  // points
589  $points = new ilNumberInputGUI($this->lng->txt("points"), "points");
590  $points->allowDecimals(true);
591  $points->setValue($this->object->getPoints() > 0 ? $this->object->getPoints() : '');
592  $points->setRequired(true);
593  $points->setSize(3);
594  $points->setMinValue(0.0);
595  $points->setMinvalueShouldBeGreater(true);
596  $form->addItem($points);
597 
599  $header->setTitle($this->lng->txt("range"));
600  $form->addItem($header);
601 
602  // lower bound
603  $lower_limit = new ilFormulaInputGUI($this->lng->txt("range_lower_limit"), "lowerlimit");
604  $lower_limit->setSize(25);
605  $lower_limit->setMaxLength(20);
606  $lower_limit->setRequired(true);
607  $lower_limit->setValue($this->object->getLowerLimit());
608  $form->addItem($lower_limit);
609 
610  // upper bound
611  $upper_limit = new ilFormulaInputGUI($this->lng->txt("range_upper_limit"), "upperlimit");
612  $upper_limit->setSize(25);
613  $upper_limit->setMaxLength(20);
614  $upper_limit->setRequired(true);
615  $upper_limit->setValue($this->object->getUpperLimit());
616  $form->addItem($upper_limit);
617 
618  // reset input length, if max chars are set
619  if ($this->object->getMaxChars() > 0) {
620  $lower_limit->setSize($this->object->getMaxChars());
621  $lower_limit->setMaxLength($this->object->getMaxChars());
622  $upper_limit->setSize($this->object->getMaxChars());
623  $upper_limit->setMaxLength($this->object->getMaxChars());
624  }
625  }
626 
631  {
632  $this->object->setPoints((float) $form->getInput('points'));
633  $this->object->setLowerLimit((float) $form->getInput('lowerlimit'));
634  $this->object->setUpperLimit((float) $form->getInput('upperlimit'));
635  }
636 }
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
This class represents a formula text property in a property form.
hasCorrectSolution($activeId, $passIndex)
addTab_QuestionPreview(ilTabsGUI $tabsGUI)
getAggregatedAnswersView($relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
addBasicQuestionFormProperties($form)
Add basic question form properties: assessment: title, author, description, question, working time.
addTab_QuestionHints(ilTabsGUI $tabs)
adds the hints tab to ilTabsGUI
$template
This class represents a property form user interface.
getPreview($show_question_only=false, $showInlineFeedback=false)
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
global $DIC
Definition: saml.php:7
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
$_GET["client_id"]
This class represents a section header in a property form.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
getAnswersFrequency($relevantAnswers, $questionIndex)
aggregateAnswers($relevant_answers_chosen)
getSpecificFeedbackOutput($userSolution)
getSolutionOutput( $active_id, $pass=null, $graphicalOutput=false, $result_output=false, $show_question_only=true, $show_feedback=false, $show_correct_solution=false, $show_manual_scoring=false, $show_question_text=true)
Get the question solution output.
if(!array_key_exists('StateId', $_REQUEST)) $id
addItem($a_item)
Add Item (Property, SectionHeader).
writePostData($always=false)
{}
getQuestionTemplate()
get question template
populateTaxonomyFormSection(ilPropertyFormGUI $form)
getUseIntermediateSolution()
Get if intermediate solution should be used for solution output.
allowDecimals($a_value)
Toggle Decimals.
setInfo($a_info)
Set Information Text.
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
checkRange($lower, $upper)
Checks the range limits.
Numeric question GUI representation.
if(isset($_POST['submit'])) $form
getILIASPage($html="")
Returns the ILIAS Page around a question.
static getImagePath($img, $module_path="", $mode="output", $offline=false)
get image path (for images located in a template directory)
This class represents a number property in a property form.
special template class to simplify handling of ITX/PEAR
setSize($a_size)
Set Size.
addTab_QuestionFeedback(ilTabsGUI $tabs)
adds the feedback tab to ilTabsGUI
supportsIntermediateSolutionOutput()
Question type specific support of intermediate solution output The function getSolutionOutput respect...
getInput($a_post_var, $ensureValidation=true)
Returns the value of a HTTP-POST variable, identified by the passed id.
Basic GUI class for assessment questions.
getTestOutput($active_id, $pass, $is_postponed=false, $use_post_solutions=false, $inlineFeedback)
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
$errors
Definition: index.php:6
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
Class for numeric questions.
addBackTab(ilTabsGUI $ilTabs)
__construct($id=-1)
assNumericGUI constructor
Interface ilGuiAnswerScoringAdjustable.
$url
renderAggregateView($aggregate)
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
Interface ilGuiQuestionScoringAdjustable.
$key
Definition: croninfo.php:18
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form)
$_POST["username"]
addTab_SuggestedSolution(ilTabsGUI $tabs, $classname)
addQuestionFormCommandButtons($form)
Add the command buttons of a question properties form.