ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilTestCorrectionsGUI.php
Go to the documentation of this file.
1 <?php
2 
3 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
4 
14 {
18  protected $DIC;
19 
23  protected $testOBJ;
24 
28  protected $testAccess;
29 
35  public function __construct(\ILIAS\DI\Container $DIC, ilObjTest $testOBJ)
36  {
37  $this->DIC = $DIC;
38  $this->testOBJ = $testOBJ;
39 
40  $this->testAccess = new ilTestAccess($testOBJ->getRefId(), $testOBJ->getTestId());
41  }
42 
43  public function executeCommand()
44  {
45  if (!$this->testAccess->checkCorrectionsAccess()) {
47  }
48 
49  if (isset($_GET['eqid']) && (int) $_GET["eqid"] && isset($_GET['eqpl']) && (int) $_GET["eqpl"]) {
50  $this->DIC->ctrl()->setParameter($this, 'qid', (int) $_GET["eqid"]);
51  $this->DIC->ctrl()->redirect($this, 'showQuestion');
52  }
53 
54  if (isset($_GET['removeQid']) && (int) $_GET['removeQid']) {
55  $this->DIC->ctrl()->setParameter($this, 'qid', (int) $_GET['removeQid']);
56  $this->DIC->ctrl()->redirect($this, 'confirmQuestionRemoval');
57  }
58 
59  if ((int) $_GET['qid'] && !$this->checkQuestion((int) $_GET['qid'])) {
61  }
62 
63  $this->DIC->ctrl()->saveParameter($this, 'qid');
64 
65  switch ($this->DIC->ctrl()->getNextClass($this)) {
66  default:
67 
68  $command = $this->DIC->ctrl()->getCmd('showQuestionList');
69  $this->{$command}();
70  }
71  }
72 
73  protected function showQuestionList()
74  {
75  $this->DIC->tabs()->activateTab(ilTestTabsManager::TAB_ID_CORRECTION);
76 
77  $ui = $this->DIC->ui();
78 
79  if ($this->testOBJ->isFixedTest()) {
80  $table_gui = new ilTestQuestionsTableGUI(
81  $this,
82  'showQuestionList',
83  $this->testOBJ->getRefId()
84  );
85 
86  $table_gui->setQuestionTitleLinksEnabled(true);
87  $table_gui->setQuestionRemoveRowButtonEnabled(true);
88  $table_gui->init();
89 
90  $table_gui->setData($this->getQuestions());
91 
92  $rendered_gui_component = $table_gui->getHTML();
93  } else {
94  $lng = $this->DIC->language();
95  $txt = $lng->txt('tst_corrections_incompatible_question_set_type');
96 
97  $infoBox = $ui->factory()->messageBox()->info($txt);
98 
99  $rendered_gui_component = $ui->renderer()->render($infoBox);
100  }
101 
102  $ui->mainTemplate()->setContent($rendered_gui_component);
103  }
104 
105  protected function showQuestion(ilPropertyFormGUI $form = null)
106  {
107  $questionGUI = $this->getQuestion((int) $_GET['qid']);
108 
109  $this->setCorrectionTabsContext($questionGUI, 'question');
110 
111  if ($form === null) {
112  $form = $this->buildQuestionCorrectionForm($questionGUI);
113  }
114 
115  $this->populatePageTitleAndDescription($questionGUI);
116  $this->DIC->ui()->mainTemplate()->setContent($form->getHTML());
117  }
118 
119  protected function saveQuestion()
120  {
121  $questionGUI = $this->getQuestion((int) $_GET['qid']);
122 
123  $form = $this->buildQuestionCorrectionForm($questionGUI);
124 
125  $form->setValuesByPost();
126 
127  if (!$form->checkInput()) {
128  $questionGUI->prepareReprintableCorrectionsForm($form);
129 
130  $this->showQuestion($form);
131  return;
132  }
133 
134  $questionGUI->saveCorrectionsFormProperties($form);
135  $questionGUI->object->setPoints($questionGUI->object->getMaximumPoints());
136  $questionGUI->object->saveToDb();
137 
138  $scoring = new ilTestScoring($this->testOBJ);
139  $scoring->setPreserveManualScores(false);
140  $scoring->setQuestionId($questionGUI->object->getId());
141  $scoring->recalculateSolutions();
142 
143  $this->DIC->ctrl()->redirect($this, 'showQuestion');
144  }
145 
146  protected function buildQuestionCorrectionForm(assQuestionGUI $questionGUI)
147  {
148  $form = new ilPropertyFormGUI();
149  $form->setFormAction($this->DIC->ctrl()->getFormAction($this));
150  $form->setId('tst_question_correction');
151 
152  $form->setTitle($this->DIC->language()->txt('tst_corrections_qst_form'));
153 
154  $hiddenQid = new ilHiddenInputGUI('qid');
155  $hiddenQid->setValue($questionGUI->object->getId());
156  $form->addItem($hiddenQid);
157 
159 
160  $scoring = new ilTestScoring($this->testOBJ);
161  $scoring->setQuestionId($questionGUI->object->getId());
162 
163  if ($scoring->getNumManualScorings()) {
164  $form->addCommandButton('confirmManualScoringReset', $this->DIC->language()->txt('save'));
165  } else {
166  $form->addCommandButton('saveQuestion', $this->DIC->language()->txt('save'));
167  }
168 
169  return $form;
170  }
171 
172  protected function addHiddenItemsFromArray(ilConfirmationGUI $gui, $array, $curPath = array())
173  {
174  foreach ($array as $name => $value) {
175  if ($name == 'cmd' && !count($curPath)) {
176  continue;
177  }
178 
179  if (count($curPath)) {
180  $name = "[{$name}]";
181  }
182 
183  if (is_array($value)) {
184  $nextPath = array_merge($curPath, array($name));
185  $this->addHiddenItemsFromArray($gui, $value, $nextPath);
186  } else {
187  $postVar = implode('', $curPath) . $name;
188  $gui->addHiddenItem($postVar, $value);
189  }
190  }
191  }
192 
193  protected function confirmManualScoringReset()
194  {
195  $questionGUI = $this->getQuestion((int) $_GET['qid']);
196 
197  $this->setCorrectionTabsContext($questionGUI, 'question');
198 
199  $scoring = new ilTestScoring($this->testOBJ);
200  $scoring->setQuestionId($questionGUI->object->getId());
201 
202  $confirmation = sprintf(
203  $this->DIC->language()->txt('tst_corrections_manscore_reset_warning'),
204  $scoring->getNumManualScorings(),
205  $questionGUI->object->getTitle(),
206  $questionGUI->object->getId()
207  );
208 
209  $gui = new ilConfirmationGUI();
210  $gui->setHeaderText($confirmation);
211  $gui->setFormAction($this->DIC->ctrl()->getFormAction($this));
212  $gui->setCancel($this->DIC->language()->txt('cancel'), 'showQuestion');
213  $gui->setConfirm($this->DIC->language()->txt('confirm'), 'saveQuestion');
214 
215  $this->addHiddenItemsFromArray($gui, $_POST);
216 
217  $this->DIC->ui()->mainTemplate()->setContent($gui->getHTML());
218  }
219 
220  protected function showSolution()
221  {
222  $questionGUI = $this->getQuestion((int) $_GET['qid']);
223 
224  $this->setCorrectionTabsContext($questionGUI, 'solution');
225 
226  $pageGUI = new ilAssQuestionPageGUI($questionGUI->object->getId());
227  $pageGUI->setRenderPageContainer(false);
228  $pageGUI->setEditPreview(true);
229  $pageGUI->setEnabledTabs(false);
230 
231  $solutionHTML = $questionGUI->getSolutionOutput(
232  0,
233  null,
234  false,
235  false,
236  true,
237  false,
238  true,
239  false,
240  true
241  );
242 
243  $pageGUI->setQuestionHTML(array($questionGUI->object->getId() => $solutionHTML));
244  $pageGUI->setPresentationTitle($questionGUI->object->getTitle());
245 
246  $tpl = new ilTemplate('tpl.tst_corrections_solution_presentation.html', true, true, 'Modules/Test');
247  $tpl->setVariable('SOLUTION_PRESENTATION', $pageGUI->preview());
248 
249  $this->populatePageTitleAndDescription($questionGUI);
250 
251  $this->DIC->ui()->mainTemplate()->setContent($tpl->get());
252  $this->DIC->ui()->mainTemplate()->addCss('Modules/Test/templates/default/ta.css');
253 
254  $this->DIC->ui()->mainTemplate()->setCurrentBlock("ContentStyle");
255  $stylesheet = ilObjStyleSheet::getContentStylePath(0);
256  $this->DIC->ui()->mainTemplate()->setVariable("LOCATION_CONTENT_STYLESHEET", $stylesheet);
257  $this->DIC->ui()->mainTemplate()->parseCurrentBlock();
258 
259  $this->DIC->ui()->mainTemplate()->setCurrentBlock("SyntaxStyle");
260  $stylesheet = ilObjStyleSheet::getSyntaxStylePath();
261  $this->DIC->ui()->mainTemplate()->setVariable("LOCATION_SYNTAX_STYLESHEET", $stylesheet);
262  $this->DIC->ui()->mainTemplate()->parseCurrentBlock();
263  }
264 
265  protected function showAnswerStatistic()
266  {
267  $questionGUI = $this->getQuestion((int) $_GET['qid']);
268  $solutions = $this->getSolutions($questionGUI->object);
269 
270  $this->setCorrectionTabsContext($questionGUI, 'answers');
271 
272  $tablesHtml = '';
273 
274  foreach ($questionGUI->getSubQuestionsIndex() as $subQuestionIndex) {
275  $table = $questionGUI->getAnswerFrequencyTableGUI(
276  $this,
277  'showAnswerStatistic',
278  $solutions,
279  $subQuestionIndex
280  );
281 
282  $tablesHtml .= $table->getHTML() . $table->getAdditionalHtml();
283  }
284 
285  $this->populatePageTitleAndDescription($questionGUI);
286  $this->DIC->ui()->mainTemplate()->setContent($tablesHtml);
287  $this->DIC->ui()->mainTemplate()->addCss('Modules/Test/templates/default/ta.css');
288  }
289 
290  protected function addAnswerAsynch()
291  {
292  $response = new stdClass();
293 
295  $form->build();
296  $form->setValuesByPost();
297 
298  if (!$form->checkInput()) {
299  $uid = md5($form->getInput('answer'));
300 
301  $form->setId($uid);
302  $form->setFormAction($this->DIC->ctrl()->getFormAction($this, 'addAnswerAsynch'));
303 
304  $alert = $this->DIC->ui()->factory()->messageBox()->failure(
305  $this->DIC->language()->txt('form_input_not_valid')
306  );
307 
308  $bodyTpl = new ilTemplate('tpl.tst_corr_addanswermodal.html', true, true, 'Modules/TestQuestionPool');
309  $bodyTpl->setVariable('MESSAGE', $this->DIC->ui()->renderer()->render($alert));
310  $bodyTpl->setVariable('FORM', $form->getHTML());
311  $bodyTpl->setVariable('BODY_UID', $uid);
312 
313  $response->result = false;
314  $response->html = $bodyTpl->get();
315 
316  echo json_encode($response);
317  exit;
318  }
319 
320  $qid = (int) $form->getInput('qid');
321 
322  if (!$this->checkQuestion($qid)) {
323  $response->html = '';
324  $response->result = false;
325 
326  echo json_encode($response);
327  exit;
328  }
329 
330  $questionGUI = $this->getQuestion($qid);
331 
332  $qIndex = (int) $form->getInput('qindex');
333  $points = (float) $form->getInput('points');
334  $answerOption = $form->getInput('answer');
335 
336  if ($questionGUI->object->isAddableAnswerOptionValue($qIndex, $answerOption)) {
337  $questionGUI->object->addAnswerOptionValue($qIndex, $answerOption, $points);
338  $questionGUI->object->saveToDb();
339  }
340 
341  $scoring = new ilTestScoring($this->testOBJ);
342  $scoring->setPreserveManualScores(true);
343  $scoring->recalculateSolutions();
344 
345  $response->result = true;
346 
347  echo json_encode($response);
348  exit;
349  }
350 
351  protected function confirmQuestionRemoval()
352  {
353  $this->DIC->tabs()->activateTab(ilTestTabsManager::TAB_ID_CORRECTION);
354 
355  $questionGUI = $this->getQuestion((int) $_GET['qid']);
356 
357  $confirmation = sprintf(
358  $this->DIC->language()->txt('tst_corrections_qst_remove_confirmation'),
359  $questionGUI->object->getTitle(),
360  $questionGUI->object->getId()
361  );
362 
363  $buttons = array(
364  $this->DIC->ui()->factory()->button()->standard(
365  $this->DIC->language()->txt('confirm'),
366  $this->DIC->ctrl()->getLinkTarget($this, 'performQuestionRemoval')
367  ),
368  $this->DIC->ui()->factory()->button()->standard(
369  $this->DIC->language()->txt('cancel'),
370  $this->DIC->ctrl()->getLinkTarget($this, 'showQuestionList')
371  )
372  );
373 
374  $this->DIC->ui()->mainTemplate()->setContent($this->DIC->ui()->renderer()->render(
375  $this->DIC->ui()->factory()->messageBox()->confirmation($confirmation)->withButtons($buttons)
376  ));
377  }
378 
379  protected function performQuestionRemoval()
380  {
381  global $DIC; /* @var ILIAS\DI\Container $DIC */
382 
383  $questionGUI = $this->getQuestion((int) $_GET['qid']);
384  $scoring = new ilTestScoring($this->testOBJ);
385 
386  $participantData = new ilTestParticipantData($DIC->database(), $DIC->language());
387  $participantData->load($this->testOBJ->getTestId());
388 
389  // remove question solutions
390  $questionGUI->object->removeAllExistingSolutions();
391 
392  // remove test question results
393  $scoring->removeAllQuestionResults($questionGUI->object->getId());
394 
395  // remove question from test and reindex remaining questions
396  $this->testOBJ->removeQuestion($questionGUI->object->getId());
397  $reindexedSequencePositionMap = $this->testOBJ->reindexFixedQuestionOrdering();
398  $this->testOBJ->loadQuestions();
399 
400  // remove questions from all sequences
401  $this->testOBJ->removeQuestionFromSequences(
402  $questionGUI->object->getId(),
403  $participantData->getActiveIds(),
404  $reindexedSequencePositionMap
405  );
406 
407  // update pass and test results
408  $scoring->updatePassAndTestResults($participantData->getActiveIds());
409 
410  // trigger learning progress
411  ilLPStatusWrapper::_refreshStatus($this->testOBJ->getId(), $participantData->getUserIds());
412 
413  // finally delete the question itself
414  $questionGUI->object->delete($questionGUI->object->getId());
415 
416  // check for empty test and set test offline
417  if (!count($this->testOBJ->getTestQuestions())) {
418  $this->testOBJ->setOnline(false);
419  $this->testOBJ->saveToDb(true);
420  }
421 
422  $this->DIC->ctrl()->setParameter($this, 'qid', '');
423  $this->DIC->ctrl()->redirect($this, 'showQuestionList');
424  }
425 
426  protected function setCorrectionTabsContext(assQuestionGUI $questionGUI, $activeTabId)
427  {
428  $this->DIC->tabs()->clearTargets();
429  $this->DIC->tabs()->clearSubTabs();
430 
431  $this->DIC->tabs()->setBackTarget(
432  $this->DIC->language()->txt('back'),
433  $this->DIC->ctrl()->getLinkTarget($this, 'showQuestionList')
434  );
435 
436  $this->DIC->tabs()->addTab(
437  'question',
438  $this->DIC->language()->txt('tst_corrections_tab_question'),
439  $this->DIC->ctrl()->getLinkTarget($this, 'showQuestion')
440  );
441 
442  $this->DIC->tabs()->addTab(
443  'solution',
444  $this->DIC->language()->txt('tst_corrections_tab_solution'),
445  $this->DIC->ctrl()->getLinkTarget($this, 'showSolution')
446  );
447 
448  if ($questionGUI->isAnswerFreuqencyStatisticSupported()) {
449  $this->DIC->tabs()->addTab(
450  'answers',
451  $this->DIC->language()->txt('tst_corrections_tab_statistics'),
452  $this->DIC->ctrl()->getLinkTarget($this, 'showAnswerStatistic')
453  );
454  }
455 
456  $this->DIC->tabs()->activateTab($activeTabId);
457  }
458 
462  protected function populatePageTitleAndDescription(assQuestionGUI $questionGUI)
463  {
464  $this->DIC->ui()->mainTemplate()->setTitle($questionGUI->object->getTitle());
465  $this->DIC->ui()->mainTemplate()->setDescription($questionGUI->outQuestionType());
466  }
467 
472  protected function checkQuestion($qId)
473  {
474  if (!$this->testOBJ->isTestQuestion($qId)) {
475  return false;
476  }
477 
478  $questionGUI = $this->getQuestion($qId);
479 
480  if (!$this->supportsAdjustment($questionGUI)) {
481  return false;
482  }
483 
484  if (!$this->allowedInAdjustment($questionGUI)) {
485  return false;
486  }
487 
488  return true;
489  }
490 
495  protected function getQuestion($qId)
496  {
497  $question = assQuestion::instantiateQuestionGUI($qId);
498  $question->object->setObjId($this->testOBJ->getId());
499 
500  return $question;
501  }
502 
503  protected function getSolutions(assQuestion $question)
504  {
505  $solutionRows = array();
506 
507  foreach ($this->testOBJ->getParticipants() as $activeId => $participantData) {
508  $passesSelector = new ilTestPassesSelector($this->DIC->database(), $this->testOBJ);
509  $passesSelector->setActiveId($activeId);
510  $passesSelector->loadLastFinishedPass();
511 
512  foreach ($passesSelector->getClosedPasses() as $pass) {
513  foreach ($question->getSolutionValues($activeId, $pass) as $row) {
514  $solutionRows[] = $row;
515  }
516  }
517  }
518 
519  return $solutionRows;
520  }
521 
525  protected function getQuestions() : array
526  {
527  $questions = array();
528 
529  foreach ($this->testOBJ->getTestQuestions() as $questionData) {
530  $questionGUI = $this->getQuestion($questionData['question_id']);
531 
532  if (!$this->supportsAdjustment($questionGUI)) {
533  continue;
534  }
535 
536  if (!$this->allowedInAdjustment($questionGUI)) {
537  continue;
538  }
539 
540  $questions[] = $questionData;
541  }
542 
543  return $questions;
544  }
545 
553  protected function supportsAdjustment(\assQuestionGUI $question_object)
554  {
555  return ($question_object instanceof ilGuiQuestionScoringAdjustable
556  || $question_object instanceof ilGuiAnswerScoringAdjustable)
557  && ($question_object->object instanceof ilObjQuestionScoringAdjustable
558  || $question_object->object instanceof ilObjAnswerScoringAdjustable);
559  }
560 
567  protected function allowedInAdjustment(\assQuestionGUI $question_object)
568  {
569  $setting = new ilSetting('assessment');
570  $types = explode(',', $setting->get('assessment_scoring_adjustment'));
571  require_once './Modules/TestQuestionPool/classes/class.ilObjQuestionPool.php';
572  $type_def = array();
573  foreach ($types as $type) {
575  }
576 
577  $type = $question_object->getQuestionType();
578  if (in_array($type, $type_def)) {
579  return true;
580  }
581  return false;
582  }
583 }
setQuestionTitleLinksEnabled(bool $questionTitleLinksEnabled)
addHiddenItem($a_post_var, $a_value)
Add hidden item.
This class represents a property form user interface.
buildQuestionCorrectionForm(assQuestionGUI $questionGUI)
$type
addHiddenItemsFromArray(ilConfirmationGUI $gui, $array, $curPath=array())
$_GET["client_id"]
$tpl
Definition: ilias.php:10
Abstract basic class which is to be extended by the concrete assessment question type classes...
Class BaseForm.
static getQuestionTypeByTypeId($type_id)
getTestId()
Gets the database id of the additional test data.
getSolutionValues($active_id, $pass=null, $authorized=true)
Loads solutions of a given user from the database an returns it.
static _refreshStatus($a_obj_id, $a_users=null)
Set dirty.
static accessViolationRedirect()
Question page GUI class.
This class represents a hidden form property in a property form.
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
setCorrectionTabsContext(assQuestionGUI $questionGUI, $activeTabId)
if(isset($_POST['submit'])) $form
$lng
Class HTTPServicesTest.
special template class to simplify handling of ITX/PEAR
Interface ilObjAnswerScoringAdjustable.
getSolutions(assQuestion $question)
allowedInAdjustment(\assQuestionGUI $question_object)
Returns if the question type is allowed for adjustments in the global test administration.
setRenderPageContainer($a_val)
Set render page container.
getQuestionType()
Returns the question type string.
static getSyntaxStylePath()
get syntax style path
static getContentStylePath($a_style_id, $add_random=true)
get content style path
Basic GUI class for assessment questions.
$txt
Definition: error.php:11
Class ilTestScoring.
supportsAdjustment(\assQuestionGUI $question_object)
Returns if the given question object support scoring adjustment.
$row
exit
Definition: backend.php:16
populatePageTitleAndDescription(assQuestionGUI $questionGUI)
__construct(\ILIAS\DI\Container $DIC, ilObjTest $testOBJ)
ilTestCorrectionsGUI constructor.
Interface ilObjQuestionScoringAdjustable.
getRefId()
get reference id public
Interface ilGuiAnswerScoringAdjustable.
if(empty($password)) $table
Definition: pwgen.php:24
Interface ilGuiQuestionScoringAdjustable.
$response
$_POST["username"]
static instantiateQuestionGUI($a_question_id)
Creates an instance of a question gui with a given question id.
showQuestion(ilPropertyFormGUI $form=null)
Confirmation screen class.