ILIAS  release_8 Revision v8.24
class.assOrderingHorizontal.php
Go to the documentation of this file.
1<?php
2
19require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20
33{
34 protected const HAS_SPECIFIC_FEEDBACK = false;
35
36 protected $ordertext;
37 protected $textsize;
38 protected $separator = "::";
39 protected $answer_separator = '{::}';
40
53 public function __construct(
54 $title = "",
55 $comment = "",
56 $author = "",
57 $owner = -1,
58 $question = ""
59 ) {
61 $this->ordertext = "";
62 }
63
69 public function isComplete(): bool
70 {
71 if (strlen($this->title) and ($this->author) and ($this->question) and ($this->getMaximumPoints() > 0)) {
72 return true;
73 } else {
74 return false;
75 }
76 }
77
82 public function saveToDb($original_id = ""): void
83 {
84 if ($original_id == "") {
85 $this->saveQuestionDataToDb();
86 } else {
88 }
89
91 parent::saveToDb();
92 }
93
97 public function getAnswerSeparator(): string
98 {
100 }
101
102
109 public function loadFromDb($question_id): void
110 {
111 global $DIC;
112 $ilDB = $DIC['ilDB'];
113
114 $result = $ilDB->queryF(
115 "SELECT qpl_questions.*, " . $this->getAdditionalTableName() . ".* FROM qpl_questions LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s",
116 array("integer"),
117 array($question_id)
118 );
119 if ($result->numRows() == 1) {
120 $data = $ilDB->fetchAssoc($result);
121 $this->setId($question_id);
122 $this->setObjId($data["obj_fi"]);
123 $this->setTitle((string) $data["title"]);
124 $this->setComment((string) $data["description"]);
125 $this->setOriginalId($data["original_id"]);
126 $this->setNrOfTries($data['nr_of_tries']);
127 $this->setAuthor($data["author"]);
128 $this->setPoints($data["points"]);
129 $this->setOwner($data["owner"]);
130 include_once("./Services/RTE/classes/class.ilRTE.php");
131 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
132 $this->setOrderText($data["ordertext"]);
133 $this->setTextSize($data["textsize"]);
134
135 try {
136 $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
139 }
140
141 try {
142 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
144 }
145 }
146
147 parent::loadFromDb($question_id);
148 }
149
153 public function duplicate(bool $for_test = true, string $title = "", string $author = "", string $owner = "", $testObjId = null): int
154 {
155 if ($this->id <= 0) {
156 // The question has not been saved. It cannot be duplicated
157 return -1;
158 }
159 // duplicate the question in database
160 $this_id = $this->getId();
161 $thisObjId = $this->getObjId();
162
163 $clone = $this;
164 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
166 $clone->id = -1;
167
168 if ((int) $testObjId > 0) {
169 $clone->setObjId($testObjId);
170 }
171
172 if ($title) {
173 $clone->setTitle($title);
174 }
175
176 if ($author) {
177 $clone->setAuthor($author);
178 }
179 if ($owner) {
180 $clone->setOwner($owner);
181 }
182
183 if ($for_test) {
184 $clone->saveToDb($original_id);
185 } else {
186 $clone->saveToDb();
187 }
188
189 // copy question page content
190 $clone->copyPageOfQuestion($this_id);
191 // copy XHTML media objects
192 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
193
194 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
195
196 return $clone->id;
197 }
198
202 public function copyObject($target_questionpool_id, $title = ""): int
203 {
204 if ($this->getId() <= 0) {
205 throw new RuntimeException('The question has not been saved. It cannot be duplicated');
206 }
207 // duplicate the question in database
208 $clone = $this;
209 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
211 $clone->id = -1;
212 $source_questionpool_id = $this->getObjId();
213 $clone->setObjId($target_questionpool_id);
214 if ($title) {
215 $clone->setTitle($title);
216 }
217 $clone->saveToDb();
218 // copy question page content
219 $clone->copyPageOfQuestion($original_id);
220 // copy XHTML media objects
221 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
222
223 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
224
225 return $clone->id;
226 }
227
228 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = ""): int
229 {
230 if ($this->getId() <= 0) {
231 throw new RuntimeException('The question has not been saved. It cannot be duplicated');
232 }
233
234 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
235
236 $sourceQuestionId = $this->id;
237 $sourceParentId = $this->getObjId();
238
239 // duplicate the question in database
240 $clone = $this;
241 $clone->id = -1;
242
243 $clone->setObjId($targetParentId);
244
245 if ($targetQuestionTitle) {
246 $clone->setTitle($targetQuestionTitle);
247 }
248
249 $clone->saveToDb();
250 // copy question page content
251 $clone->copyPageOfQuestion($sourceQuestionId);
252 // copy XHTML media objects
253 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
254
255 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
256
257 return $clone->id;
258 }
259
265 public function getMaximumPoints(): float
266 {
267 return $this->getPoints();
268 }
269
280 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
281 {
282 if ($returndetails) {
283 throw new ilTestException('return details not implemented for ' . __METHOD__);
284 }
285
286 global $DIC;
287 $ilDB = $DIC['ilDB'];
288
289 $found_values = array();
290 if (is_null($pass)) {
291 $pass = $this->getSolutionMaxPass($active_id);
292 }
293 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
294 $points = 0;
295
296 if ($ilDB->numRows($result) > 0) {
297 $data = $ilDB->fetchAssoc($result);
299 }
300
301 return $points;
302 }
303
313 public function splitAndTrimOrderElementText(string $in_string, string $separator): array
314 {
315 $result = array();
316 include_once "./Services/Utilities/classes/class.ilStr.php";
317
318 if (ilStr::strPos($in_string, $separator) === false) {
319 $result = preg_split("/\\s+/", $in_string);
320 } else {
321 $result = explode($separator, $in_string);
322 }
323
324 foreach ($result as $key => $value) {
325 $result[$key] = trim($value);
326 }
327
328 return $result;
329 }
330
331 public function getSolutionSubmit()
332 {
333 return $_POST["orderresult"];
334 }
335
344 public function saveWorkingData($active_id, $pass = null, $authorized = true): bool
345 {
346 global $DIC;
347 if ($DIC->testQuestionPool()->internal()->request()->raw('test_answer_changed') === null) {
348 return true;
349 }
350
351 global $DIC;
352 $ilDB = $DIC['ilDB'];
353 $ilUser = $DIC['ilUser'];
354
355 if (is_null($pass)) {
356 include_once "./Modules/Test/classes/class.ilObjTest.php";
357 $pass = ilObjTest::_getPass($active_id);
358 }
359
360 $entered_values = false;
361
362 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $active_id, $pass, $authorized) {
363 $this->removeCurrentSolution($active_id, $pass, $authorized);
364
365 $solutionSubmit = $this->getSolutionSubmit();
366
367 $entered_values = false;
368 if (strlen($solutionSubmit)) {
369 $this->saveCurrentSolution($active_id, $pass, $_POST['orderresult'], null, $authorized);
370 $entered_values = true;
371 }
372 });
373
374 if ($entered_values) {
375 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
377 assQuestion::logAction($this->lng->txtlng(
378 "assessment",
379 "log_user_entered_values",
381 ), $active_id, $this->getId());
382 }
383 } else {
384 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
386 assQuestion::logAction($this->lng->txtlng(
387 "assessment",
388 "log_user_not_entered_values",
390 ), $active_id, $this->getId());
391 }
392 }
393
394 return true;
395 }
396
398 {
399 global $DIC;
400 $ilDB = $DIC['ilDB'];
401
402 // save additional data
403 $ilDB->manipulateF(
404 "DELETE FROM " . $this->getAdditionalTableName()
405 . " WHERE question_fi = %s",
406 array( "integer" ),
407 array( $this->getId() )
408 );
409
410 $ilDB->manipulateF(
411 "INSERT INTO " . $this->getAdditionalTableName()
412 . " (question_fi, ordertext, textsize) VALUES (%s, %s, %s)",
413 array( "integer", "text", "float" ),
414 array(
415 $this->getId(),
416 $this->getOrderText(),
417 ($this->getTextSize() < 10) ? null : (float) $this->getTextSize()
418 )
419 );
420 }
421
427 public function getQuestionType(): string
428 {
429 return "assOrderingHorizontal";
430 }
431
437 public function getAdditionalTableName(): string
438 {
439 return "qpl_qst_horder";
440 }
441
447 public function getAnswerTableName(): string
448 {
449 return "";
450 }
451
457 public function deleteAnswers($question_id): void
458 {
459 }
460
465 public function getRTETextWithMediaObjects(): string
466 {
467 $text = parent::getRTETextWithMediaObjects();
468 return $text;
469 }
470
474 public function setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass): int
475 {
476 parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
477
478 $solutionvalue = "";
479 $solutions = $this->getSolutionValues($active_id, $pass);
480 if (array_key_exists(0, $solutions)) {
481 $solutionvalue = str_replace("{::}", " ", $solutions[0]["value1"]);
482 }
483 $i = 1;
484 $worksheet->setCell($startrow + $i, 2, $solutionvalue);
485 $i++;
486
487 return $startrow + $i + 1;
488 }
489
502 public function fromXML($item, int $questionpool_id, ?int $tst_id, &$tst_object, int &$question_counter, array $import_mapping, array &$solutionhints = []): array
503 {
504 include_once "./Modules/TestQuestionPool/classes/import/qti12/class.assOrderingHorizontalImport.php";
505 $import = new assOrderingHorizontalImport($this);
506 return $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
507 }
508
515 public function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false): string
516 {
517 include_once "./Modules/TestQuestionPool/classes/export/qti12/class.assOrderingHorizontalExport.php";
518 $export = new assOrderingHorizontalExport($this);
519 return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
520 }
521
527 public function getBestSolution($active_id, $pass): array
528 {
529 $user_solution = array();
530 return $user_solution;
531 }
532
538 public function getOrderingElements(): array
539 {
540 return $this->splitAndTrimOrderElementText($this->getOrderText() ?? "", $this->separator);
541 }
542
548 public function getRandomOrderingElements(): array
549 {
550 $elements = $this->getOrderingElements();
551 $elements = $this->getShuffler()->transform($elements);
552 return $elements;
553 }
554
560 public function getOrderText()
561 {
562 return $this->ordertext;
563 }
564
570 public function setOrderText($a_value): void
571 {
572 $this->ordertext = $a_value;
573 }
574
580 public function getTextSize()
581 {
582 return $this->textsize;
583 }
584
590 public function setTextSize($a_value): void
591 {
592 if ($a_value >= 10) {
593 $this->textsize = $a_value;
594 }
595 }
596
602 public function getSeparator(): string
603 {
604 return $this->separator;
605 }
606
612 public function setSeparator($a_value): void
613 {
614 $this->separator = $a_value;
615 }
616
617 public function supportsJavascriptOutput(): bool
618 {
619 return true;
620 }
621
622 public function supportsNonJsOutput(): bool
623 {
624 return false;
625 }
626
630 public function toJSON(): string
631 {
632 include_once("./Services/RTE/classes/class.ilRTE.php");
633 $result = array();
634 $result['id'] = $this->getId();
635 $result['type'] = (string) $this->getQuestionType();
636 $result['title'] = $this->getTitleForHTMLOutput();
637 $result['question'] = $this->formatSAQuestion($this->getQuestion());
638 $result['nr_of_tries'] = $this->getNrOfTries();
639 $result['shuffle'] = true;
640 $result['points'] = (bool) $this->getPoints();
641 $result['textsize'] = ((int) $this->getTextSize()) // #10923
642 ? (int) $this->getTextSize()
643 : 100;
644 $result['feedback'] = array(
645 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
646 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
647 );
648
649 $arr = array();
650 foreach ($this->getOrderingElements() as $order => $answer) {
651 array_push($arr, array(
652 "answertext" => (string) $answer,
653 "order" => (int) $order + 1
654 ));
655 }
656 $result['answers'] = $arr;
657
658 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
659 $result['mobs'] = $mobs;
660
661 return json_encode($result);
662 }
663
672 public function getOperators($expression): array
673 {
675 }
676
681 public function getExpressionTypes(): array
682 {
683 return array(
688 );
689 }
690
699 public function getUserQuestionResult($active_id, $pass): ilUserQuestionResult
700 {
702 global $DIC;
703 $ilDB = $DIC['ilDB'];
704 $result = new ilUserQuestionResult($this, $active_id, $pass);
705
706 $maxStep = $this->lookupMaxStep($active_id, $pass);
707
708 if ($maxStep !== null) {
709 $data = $ilDB->queryF(
710 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
711 array("integer", "integer", "integer","integer"),
712 array($active_id, $pass, $this->getId(), $maxStep)
713 );
714 } else {
715 $data = $ilDB->queryF(
716 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
717 array("integer", "integer", "integer"),
718 array($active_id, $pass, $this->getId())
719 );
720 }
721 $row = $ilDB->fetchAssoc($data);
722
723 $answer_elements = $this->splitAndTrimOrderElementText($row["value1"] ?? "", $this->answer_separator);
724 $elements = $this->getOrderingElements();
725 $solutions = array();
726
727 foreach ($answer_elements as $answer) {
728 foreach ($elements as $key => $element) {
729 if ($element == $answer) {
730 $result->addKeyValue($key + 1, $answer);
731 }
732 }
733 }
734
735 $glue = " ";
736 if ($this->answer_separator = '{::}') {
737 $glue = "";
738 }
739 $result->addKeyValue(null, join($glue, $answer_elements));
740
741 $points = $this->calculateReachedPoints($active_id, $pass);
742 $max_points = $this->getMaximumPoints();
743
744 $result->setReachedPercentage(($points / $max_points) * 100);
745
746 return $result;
747 }
748
757 public function getAvailableAnswerOptions($index = null)
758 {
759 $elements = $this->getOrderingElements();
760 if ($index !== null) {
761 if (array_key_exists($index, $elements)) {
762 return $elements[$index];
763 }
764 return null;
765 } else {
766 return $elements;
767 }
768 }
769
774 protected function calculateReachedPointsForSolution($value): float
775 {
776 $value = $this->splitAndTrimOrderElementText($value ?? "", $this->answer_separator);
777 $value = join($this->answer_separator, $value);
778 if (strcmp($value, join($this->answer_separator, $this->getOrderingElements())) == 0) {
779 $points = $this->getPoints();
780 return $points;
781 }
782 return 0;
783 }
784
785 // fau: testNav - new function getTestQuestionConfig()
790 // hey: refactored identifiers
792 // hey.
793 {
794 // hey: refactored identifiers
795 return parent::buildTestPresentationConfig()
796 // hey.
798 ->setUseUnchangedAnswerLabel($this->lng->txt('tst_unchanged_order_is_correct'));
799 }
800 // fau.
801}
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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setSeparator($a_value)
Set order text separator.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
copyObject($target_questionpool_id, $title="")
Copies an assOrderingHorizontal object.
splitAndTrimOrderElementText(string $in_string, string $separator)
Splits the answer string either by space(s) or the separator (eg.
isComplete()
Returns true, if a single choice question is complete for use.
saveToDb($original_id="")
Saves a assOrderingHorizontal object to a database.
setOrderText($a_value)
Set order text.
setTextSize($a_value)
Set text size.
getOperators($expression)
Get all available operations for a specific question.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
toJSON()
Returns a JSON representation of the question.
getAnswerTableName()
Returns the name of the answer table in the database.
setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass)
{}
loadFromDb($question_id)
Loads a assOrderingHorizontal object from a database.
getRandomOrderingElements()
Get ordering elements from order text in random sequence.
getOrderingElements()
Get ordering elements from order text.
getQuestionType()
Returns the question type of the question.
toXML($a_include_header=true, $a_include_binary=true, $a_shuffle=false, $test_output=false, $force_image_references=false)
Returns a QTI xml representation of the question and sets the internal domxml variable with the DOM X...
getSeparator()
Get order text separator.
buildTestPresentationConfig()
Get the test question configuration.
getExpressionTypes()
Get all available expression types for a specific question.
deleteAnswers($question_id)
Deletes datasets from answers tables.
duplicate(bool $for_test=true, string $title="", string $author="", string $owner="", $testObjId=null)
Duplicates an assOrderingHorizontal.
fromXML($item, int $questionpool_id, ?int $tst_id, &$tst_object, int &$question_counter, array $import_mapping, array &$solutionhints=[])
Creates a question from a QTI file.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assOrderingHorizontal constructor
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
getBestSolution($active_id, $pass)
Returns the best solution for a given pass of a participant.
Abstract basic class which is to be extended by the concrete assessment question type classes.
float $points
The maximum available points for the question.
setOriginalId(?int $original_id)
string $question
The question text.
static logAction(string $logtext, int $active_id, int $question_id)
setId(int $id=-1)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
setQuestion(string $question="")
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
static _getOriginalId(int $question_id)
saveQuestionDataToDb(int $original_id=-1)
setAuthor(string $author="")
setComment(string $comment="")
setObjId(int $obj_id=0)
getSolutionMaxPass(int $active_id)
setOwner(int $owner=-1)
setNrOfTries(int $a_nr_of_tries)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
setTitle(string $title="")
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
lookupMaxStep(int $active_id, int $pass)
setPoints(float $points)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setCell($a_row, $a_col, $a_value, $datatype=null)
static _getMobsOfObject(string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
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...
static strPos(string $a_haystack, string $a_needle, ?int $a_offset=null)
Definition: class.ilStr.php:42
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...
setIsUnchangedAnswerPossible($isUnchangedAnswerPossible)
Set if the saving of an unchanged answer is supported with an additional checkbox.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
global $DIC
Definition: feed.php:28
$mobs
Definition: imgupload.php:70
$ilUser
Definition: imgupload.php:34
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$index
Definition: metadata.php:145
$i
Definition: metadata.php:41
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
string $key
Consumer key/client ID value.
Definition: System.php:193