19 declare(strict_types=1);
71 protected int $ordering_type = self::OQ_TERMS
79 if ($elements_list === [] && $this->element_list_for_deferred_saving !== null) {
80 $elements_list = $this->element_list_for_deferred_saving->getElements();
82 $elements = array_filter(
84 fn($element) => trim($element->getContent()) !=
'' 87 $has_at_least_two_elements = count($elements) > 1;
93 && $has_at_least_two_elements;
100 if (is_null($this->oq_repository)) {
111 if ($this->element_list_for_deferred_saving !== null) {
125 $result = $this->db->queryF(
130 if ($result->numRows() == 1) {
131 $data = $this->db->fetchAssoc($result);
132 $this->
setId($question_id);
135 $this->
setComment((
string) $data[
"description"]);
142 $this->ordering_type = $data[
"ordering_type"] !== null ? (
int) $data[
"ordering_type"] : self::OQ_TERMS;
143 if ($data[
'thumb_geometry'] !== null && $data[
'thumb_geometry'] >= $this->
getMinimumThumbSize()) {
146 $this->element_height = $data[
"element_height"] ? (
int) $data[
'element_height'] : null;
160 parent::loadFromDb($question_id);
167 ->withQuestionId($target->
getId());
168 $list->distributeNewRandomIdentifiers();
169 $target->setOrderingElementList($list);
176 int $source_question_id,
177 int $source_parent_id,
178 int $target_question_id,
179 int $target_parent_id
185 $image_source_path = $this->
getImagePath($source_question_id, $source_parent_id);
186 $image_target_path = $this->
getImagePath($target_question_id, $target_parent_id);
188 if (!file_exists($image_target_path)) {
200 if (!file_exists($image_source_path .
$filename)
201 || !copy($image_source_path . $filename, $image_target_path . $filename)) {
202 $this->log->root()->warning(
'Image could not be cloned for object for question: ' . $target_question_id);
204 if (!file_exists($image_source_path . $this->
getThumbPrefix() . $filename)
206 $this->log->root()->warning(
'Image thumbnails could not be cloned for object for question: ' . $target_question_id);
216 self::OQ_NESTED_PICTURES,
217 self::OQ_NESTED_TERMS
224 throw new \InvalidArgumentException(
'Must be valid ordering type.');
226 $this->ordering_type = $ordering_type;
231 return $this->ordering_type;
237 self::OQ_NESTED_TERMS,
238 self::OQ_NESTED_PICTURES
247 self::OQ_NESTED_PICTURES
255 self::OQ_CT_PICTURES,
258 throw new \InvalidArgumentException(
"use OQ content-type", 1);
260 if ($ct == self::OQ_CT_PICTURES) {
268 if ($ct == self::OQ_CT_TERMS) {
300 bool $force_correct_solution,
304 if ($force_correct_solution || !$active_id || $pass_index === null) {
310 if (!count($solution_values)) {
332 if (count($indexedSolutionValues)) {
343 $value = explode(
':', $value2);
345 $random_identifier = (
int) $value[0];
346 $selected_position = $value1;
347 $selected_indentation = (
int) $value[1];
351 $element->setPosition($selected_position);
352 $element->setIndentation($selected_indentation);
361 $solution_identifier = $value1;
362 $selected_position = ($value2 - 1);
363 $selected_indentation = 0;
365 $element = $this->
getOrderingElementList()->getElementBySolutionIdentifier($solution_identifier)->getClone();
367 $element->setPosition($selected_position);
368 $element->setIndentation($selected_indentation);
379 $solution_ordering_list->setQuestionId($this->
getId());
381 foreach ($indexed_solution_values as $value1 => $value2) {
388 $solution_ordering_list->addElement($element);
395 return $solution_ordering_list;
405 $shuffledRandomIdentifierIndex = $this->
getShuffler()->transform(
410 $shuffledElementList->reorderByRandomIdentifiers($shuffledRandomIdentifierIndex);
411 $shuffledElementList->resetElementsIndentations();
413 return $shuffledElementList;
429 if ($this->
getId() <= 0) {
430 $this->element_list_for_deferred_saving = $list;
436 foreach ($elements as
$e) {
475 bool $authorized_solution =
true 477 if ($pass === null) {
481 $solution_value_pairs = $this->
getSolutionValues($active_id, $pass, $authorized_solution);
483 if ($solution_value_pairs === []) {
500 $solution_ordering_element_list = unserialize(
502 [
'allowed_classes' =>
true]
529 if (preg_match(
"/.*\\.(\\w+)$/",
$filename, $matches)) {
530 $extension = $matches[1];
532 return md5(
$filename) .
"." . $extension;
540 foreach ($contents as
$f) {
541 if (strcmp($f[
'type'],
'file') == 0) {
544 if (strcmp($f[
'entry'], $orderElement->getContent()) == 0) {
547 if (strcmp($f[
'entry'], $this->
getThumbPrefix() . $orderElement->getContent()) == 0) {
552 if (@file_exists($this->
getImagePath() . $f[
'entry'])) {
574 if (!strlen($imageFilename)) {
578 $result = @unlink($this->
getImagePath() . $imageFilename);
586 if (!strlen($imageFilename)) {
590 if (!file_exists($this->
getImagePath() . $imageFilename)) {
611 public function storeImageFile(
string $upload_file,
string $upload_name): ?string
613 $name_parts = explode(
".", $upload_name);
614 $suffix = strtolower(array_pop($name_parts));
615 if (!in_array($suffix, self::VALID_UPLOAD_SUFFIXES)) {
621 $target_filepath = $this->
getImagePath() . $target_filename;
626 return $target_filename;
634 $existing_image_path = $this->
getImagePath() . $existing_image_name;
636 $target_filepath = $this->
getImagePath() . $target_filename;
642 return $target_filename;
645 return $existing_image_name;
652 if (!$submittedSolutionList->hasElements()) {
662 bool $authorized =
true 664 if ($this->questionpool_request->raw(
'test_answer_changed') === null) {
668 if (is_null($pass)) {
673 function () use ($active_id, $pass, $authorized) {
677 $value1 = $orderingElement->getStorageValue1($this->
getOrderingType());
678 $value2 = $orderingElement->getStorageValue2($this->
getOrderingType());
680 $this->
saveCurrentSolution($active_id, $pass, $value1, trim((
string) $value2), $authorized);
698 $this->db->manipulateF(
704 $this->db->manipulateF(
705 "INSERT INTO " . $this->
getAdditionalTableName() .
" (question_fi, ordering_type, thumb_geometry, element_height) 706 VALUES (%s, %s, %s, %s)",
707 [
"integer",
"text",
"integer",
"integer"],
710 $this->ordering_type,
735 return "assOrderingQuestion";
746 return "qpl_qst_ordering";
757 return "qpl_a_ordering";
766 $text = parent::getRTETextWithMediaObjects();
769 $text .= $orderingElement->getContent();
791 $this->element_height = ($a_height < 20) ? null : $a_height;
801 if ($orderingElement->getContent() !==
'') {
820 switch (strtoupper($path_info[
'extension'])) {
841 $result[
'id'] = $this->
getId();
846 $result[
'shuffle'] =
true;
848 $result[
'feedback'] = [
849 'onenotcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
850 'allcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
859 $answers[$counter] = $orderingElement->getContent();
862 $answers = $this->
getShuffler()->transform($answers);
864 foreach ($answers as $order => $answer) {
866 "answertext" => (
string) $answer,
867 "order" => (
int) $order
870 $result[
'answers'] = $arr;
873 $result[
'mobs'] = $mobs;
875 return json_encode($result);
898 $formField->setInteractionEnabled(
true);
906 $formField->setEditElementOccuranceEnabled(
true);
907 $formField->setEditElementOrderEnabled(
true);
916 $formField->
setInfo($this->
lng->txt(
'ordering_answer_sequence_info'));
929 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
934 return $orderingElementInput;
946 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
949 $orderingElementInput->setImageUploadCommand(self::ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG);
950 $orderingElementInput->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
954 return $orderingElementInput;
965 $form_data_converter,
966 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
969 $ordering_element_input->setUniquePrefix($this->
getId());
971 $ordering_element_input->setElementImagePath($this->
getImagePathWeb());
976 return $ordering_element_input;
983 $ordering_gui->setValueByArray($user_solution_post);
985 if (!$ordering_gui->checkInput()) {
993 foreach ($ordering_gui->getElementList($this->getId()) as $submitted_element) {
994 $solution_element = $stored_element_list->getElementByRandomIdentifier(
995 $submitted_element->getRandomIdentifier()
998 $solution_element->setPosition($submitted_element->getPosition());
1001 $solution_element->setIndentation($submitted_element->getIndentation());
1004 $solution_ordering_element_list->addElement($solution_element);
1007 return $solution_ordering_element_list;
1014 if ($this->postSolutionOrderingElementList === null) {
1016 $this->
http->request()->getParsedBody()
1018 $this->postSolutionOrderingElementList = $list;
1029 $user_element = $solution_ordering_element_list->
getElementByPosition($correct_element->getPosition());
1030 if (!$correct_element->isSameElement($user_element)) {
1031 $reached_points = 0;
1036 return $reached_points;
1041 return ilOperatorsExpressionMapping::getOperatorsByExpression($expression);
1062 $data = $this->db->queryF(
1063 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s ORDER BY value1 ASC ",
1064 [
"integer",
"integer",
"integer",
"integer"],
1065 [$active_id, $pass, $this->
getId(), $maxStep]
1068 $data = $this->db->queryF(
1069 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s ORDER BY value1 ASC ",
1070 [
"integer",
"integer",
"integer"],
1071 [$active_id, $pass, $this->
getId()]
1076 while ($row = $this->db->fetchAssoc(
$data)) {
1077 $newKey = explode(
":", $row[
"value2"]);
1082 if ($answer->getSolutionIdentifier() == $row[
"value1"]) {
1083 $elements[$row[
"value2"]] = $answer->getSolutionIdentifier() + 1;
1087 if ($answer->getRandomIdentifier() == $newKey[0]) {
1088 $elements[$row[
"value1"]] = $answer->getSolutionIdentifier() + 1;
1097 foreach (array_values($elements) as $element) {
1098 $result->addKeyValue($element, $element);
1104 $result->setReachedPercentage((
$points / $max_points) * 100);
1118 if ($index !== null) {
1135 return parent::buildTestPresentationConfig()
1138 ->setUseUnchangedAnswerLabel($this->
lng->txt(
'tst_unchanged_order_is_correct'));
1154 $solution_submit = [];
1156 if (isset($form_submission_data_structure[
'orderresult'])) {
1157 $orderresult = $form_submission_data_structure[
'orderresult'];
1159 if (strlen($orderresult)) {
1160 $orderarray = explode(
":", $orderresult);
1162 foreach ($orderarray as $index) {
1164 if (preg_match(
"/id_(\\d+)/", $index, $idmatch)) {
1165 $randomid = $idmatch[1];
1167 if ($answer->getRandomIdentifier() == $randomid) {
1168 $solution_submit[$answeridx] = $ordervalue;
1177 foreach ($form_submission_data_structure[
'content'] as $randomId => $content) {
1178 $indentation = $form_submission_data_structure[
'indentation'];
1181 $value2 = implode(
':', [$randomId, $indentation]);
1183 $solution_submit[$value1] = $value2;
1186 foreach ($form_submission_data_structure as $key => $value) {
1188 if (preg_match(
"/^order_(\d+)/", $key, $matches)) {
1189 if (!(preg_match(
"/initial_value_\d+/", $value))) {
1190 if (strlen($value)) {
1192 if ($answer->getRandomIdentifier() == $matches[1]) {
1193 $solution_submit[$answeridx] = $value;
1202 return $solution_submit;
1211 $converter->setPostVar(self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR);
1224 $formDataConverter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1226 $formDataConverter->setImageFsPath($this->
getImagePath());
1231 return $formDataConverter;
1241 return $form_data_converter;
1253 $form_data_converter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1255 $form_data_converter->setThumbnailPrefix($this->
getThumbPrefix());
1258 return $form_data_converter;
1264 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->
getQuestionType(),
1267 AdditionalInformationGenerator::KEY_QUESTION_ORDERING_NESTING_TYPE => array_reduce(
1269 static fn(
string $string,
string $lang_var) => $string . $additional_info->
getTagForLangVar($lang_var),
1272 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $this->
getPoints(),
1274 AdditionalInformationGenerator::KEY_FEEDBACK => [
1275 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
1276 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
1283 switch ($ordering_type) {
1284 case self::OQ_PICTURES:
1285 return [
'qst_nested_nested_answers_off',
'oq_btn_use_order_pictures'];
1286 case self::OQ_TERMS:
1287 return [
'qst_nested_nested_answers_off',
'oq_btn_use_order_terms'];
1288 case self::OQ_NESTED_PICTURES:
1289 return [
'qst_nested_nested_answers_on',
'oq_btn_use_order_pictures'];
1290 case self::OQ_NESTED_TERMS:
1291 return [
'qst_nested_nested_answers_on',
'oq_btn_use_order_terms'];
1303 $answers_gui->setInteractionEnabled(
false);
1304 $answers_gui->setElementList($solution_ordering_list);
1306 return $answers_gui->getHTML();
1311 array $solution_values
1313 if ($solution_values === []) {
1325 if ($solution_values === []) {
1359 $indentation .=
' |';
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...
ilAssOrderingElementList $element_list_for_deferred_saving
setNrOfTries(int $a_nr_of_tries)
initOrderingElementAuthoringProperties(ilFormPropertyGUI $formField)
getSolutionValues(int $active_id, ?int $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstance($identifier)
updateImageFile(string $existing_image_name)
const HAS_SPECIFIC_FEEDBACK
const PercentageResultExpression
solutionValuesToText(array $solution_values)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
buildOrderingImagesFormDataConverter()
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
setOrderingType(int $ordering_type=self::OQ_TERMS)
const VALID_UPLOAD_SUFFIXES
setIsUnchangedAnswerPossible($isUnchangedAnswerPossible)
Set if the saving of an unchanged answer is supported with an additional checkbox.
buildOrderingImagesInputGui()
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
getCorrectSolutionForTextOutput(int $active_id, int $pass)
saveWorkingData(int $active_id, ?int $pass=null, bool $authorized=true)
buildOrderingTextsFormDataConverter()
withElements(array $elements)
removeAllImageFiles(string $image_target_path)
getSolutionListFromPostSubmit()
ensureNonNegativePoints(float $points)
initOrderingElementFormFieldLabels(ilFormPropertyGUI $formField)
getQuestionType()
Returns the question type of the question.
getOrderElements()
Returns the answers array.
getImagePathWeb()
Returns the web image path for web accessable images of a question.
setThumbSize(int $a_size)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static buildInstance(int $question_id, array $elements=[])
setOrderingElementList(ilAssOrderingElementList $list)
savePreviewData(ilAssQuestionPreviewSession $previewSession)
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
getParticipantsSolution()
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
setComment(string $comment="")
isImageReplaced(ilAssOrderingElement $newElement, ilAssOrderingElement $oldElement)
Base Exception for all Exceptions relating to Modules/Test.
dropImageFile($imageFilename)
buildOrderingElementInputGui()
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
setParticipantsSolution($participantSolution)
getAnswer(int $index=0)
Returns the ordering element from the given position.
setElementHeight(?int $a_height)
__construct(string $title="", string $comment="", string $author="", int $owner=-1, string $question="", protected int $ordering_type=self::OQ_TERMS)
buildOrderingElementFormDataConverter()
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
getSolutionValuePairBrandedOrderingElementByRandomIdentifier(int $value1, string $value2)
static http()
Fetches the global http state from ILIAS.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
solutionValuesToLog(AdditionalInformationGenerator $additional_info, array $solution_values)
getExpressionTypes()
Get all available expression types for a specific question.
buildHashedImageFilename(string $plain_image_filename, bool $unique=false)
const ORDERING_ELEMENT_FORM_FIELD_POSTVAR
fetchSolutionSubmit(array $form_submission_data_structure)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAnswerTableName()
Returns the name of the answer table in the database.
const NumericResultExpression
deleteAnswer(int $random_identifier)
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
toJSON()
Returns a JSON representation of the question.
deductHintPointsFromReachedPoints(ilAssQuestionPreviewSession $preview_session, $reached_points)
buildNestedOrderingFormDataConverter()
cloneQuestionTypeSpecificProperties(\assQuestion $target)
const ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG
getElementArrayWithIdentationsForTextOutput(array $elements)
getSolutionOutputForLog()
static getDir(string $a_dir, bool $a_rec=false, ?string $a_sub_dir="")
get directory
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
saveQuestionDataToDb(?int $original_id=null)
const OrderingResultExpression
static convertImage(string $a_from, string $a_to, string $a_target_format="", string $a_geometry="", string $a_background_color="")
getEncryptedFilename($filename)
saveToDb(?int $original_id=null)
fetchIndexedValuesFromValuePairs(array $value_pairs)
fetchSolutionListFromFormSubmissionData(array $user_solution_post)
getSolutionMaxPass(int $active_id)
setNestingType(bool $nesting)
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
storeImageFile(string $upload_file, string $upload_name)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
OQRepository $oq_repository
__construct(Container $dic, ilPlugin $plugin)
setOriginalId(?int $original_id)
ilAssOrderingElementList $postSolutionOrderingElementList
getTestOutputSolutions(int $activeId, int $pass)
cloneImages(int $source_question_id, int $source_parent_id, int $target_question_id, int $target_parent_id)
setTitle(string $title="")
Class for ordering questions.
buildOrderingTextsInputGui()
getOperators(string $expression)
Get all available operations for a specific question.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
setLifecycle(ilAssQuestionLifecycle $lifecycle)
toLog(AdditionalInformationGenerator $additional_info)
getShuffledOrderingElementList()
getElementByPosition(int $position)
buildTestPresentationConfig()
Get the test question configuration.
static rename(string $a_source, string $a_target)
getSolutionOrderingElementList(array $indexed_solution_values)
calculateReachedPoints(int $active_id, ?int $pass=null, bool $authorized_solution=true)
saveToDb(?int $original_id=null)
hasOrderingTypeUploadSupport()
isImageFileStored($imageFilename)
getSolutionOrderingElementListForTestOutput(ilAssNestedOrderingElementsInputGUI $input_gui, array $last_post, int $active_id, int $pass)
lookupMaxStep(int $active_id, int $pass)
setAuthor(string $author="")
getOrderingElementListForSolutionOutput(bool $force_correct_solution, int $active_id, ?int $pass_index)
buildNestedOrderingElementInputGui()
getUserQuestionResult(int $active_id, int $pass)
Get the user solution for a question by active_id and the test pass.
withQuestionId(int $question_id)
calculateReachedPointsForSolution(ilAssOrderingElementList $solution_ordering_element_list)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
loadFromDb($question_id)
Loads a assOrderingQuestion object from a database.
getSolutionValuePairBrandedOrderingElementBySolutionIdentifier(int $value1, string $value2)
generateThumbForFile($path, $file)
static getDraftInstance()
ensureValidIdentifiers(ilAssOrderingElement $element)
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
getOrderingTypeLangVars(int $ordering_type)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAdditionalTableName()
Returns the name of the additional question data table in the database.
const ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG
setQuestion(string $question="")
const EmptyAnswerExpression
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $preview_session)