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;
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);
175 int $source_question_id,
176 int $source_parent_id,
177 int $target_question_id,
178 int $target_parent_id
184 $image_source_path = $this->
getImagePath($source_question_id, $source_parent_id);
185 $image_target_path = $this->
getImagePath($target_question_id, $target_parent_id);
187 if (!file_exists($image_target_path)) {
199 if (!file_exists($image_source_path .
$filename)
200 || !copy($image_source_path . $filename, $image_target_path . $filename)) {
201 $this->log->root()->warning(
'Image could not be cloned for object for question: ' . $target_question_id);
203 if (!file_exists($image_source_path . $this->
getThumbPrefix() . $filename)
205 $this->log->root()->warning(
'Image thumbnails could not be cloned for object for question: ' . $target_question_id);
215 self::OQ_NESTED_PICTURES,
216 self::OQ_NESTED_TERMS
223 throw new \InvalidArgumentException(
'Must be valid ordering type.');
225 $this->ordering_type = $ordering_type;
230 return $this->ordering_type;
236 self::OQ_NESTED_TERMS,
237 self::OQ_NESTED_PICTURES
246 self::OQ_NESTED_PICTURES
254 self::OQ_CT_PICTURES,
257 throw new \InvalidArgumentException(
"use OQ content-type", 1);
259 if ($ct == self::OQ_CT_PICTURES) {
267 if ($ct == self::OQ_CT_TERMS) {
299 bool $force_correct_solution,
303 if ($force_correct_solution || !$active_id || $pass_index ===
null) {
309 if (!count($solution_values)) {
331 if (count($indexedSolutionValues)) {
342 $value = explode(
':', $value2);
344 $random_identifier = (
int) $value[0];
345 $selected_position = $value1;
346 $selected_indentation = (
int) $value[1];
350 $element->setPosition($selected_position);
351 $element->setIndentation($selected_indentation);
360 $solution_identifier = $value1;
361 $selected_position = ($value2 - 1);
362 $selected_indentation = 0;
364 $element = $this->
getOrderingElementList()->getElementBySolutionIdentifier($solution_identifier)->getClone();
366 $element->setPosition($selected_position);
367 $element->setIndentation($selected_indentation);
378 $solution_ordering_list->setQuestionId($this->
getId());
380 foreach ($indexed_solution_values as $value1 => $value2) {
387 $solution_ordering_list->addElement($element);
394 return $solution_ordering_list;
404 $shuffledRandomIdentifierIndex = $this->
getShuffler()->transform(
409 $shuffledElementList->reorderByRandomIdentifiers($shuffledRandomIdentifierIndex);
410 $shuffledElementList->resetElementsIndentations();
412 return $shuffledElementList;
428 if ($this->
getId() <= 0) {
429 $this->element_list_for_deferred_saving = $list;
435 foreach ($elements as
$e) {
474 bool $authorized_solution =
true 476 if ($pass ===
null) {
480 $solution_value_pairs = $this->
getSolutionValues($active_id, $pass, $authorized_solution);
482 if ($solution_value_pairs === []) {
499 $solution_ordering_element_list = unserialize(
501 [
'allowed_classes' =>
true]
528 if (preg_match(
"/.*\\.(\\w+)$/",
$filename, $matches)) {
529 $extension = $matches[1];
531 return md5(
$filename) .
"." . $extension;
539 foreach ($contents as
$f) {
540 if (strcmp($f[
'type'],
'file') == 0) {
543 if (strcmp($f[
'entry'], $orderElement->getContent()) == 0) {
546 if (strcmp($f[
'entry'], $this->
getThumbPrefix() . $orderElement->getContent()) == 0) {
551 if (@file_exists($this->
getImagePath() . $f[
'entry'])) {
573 if (!strlen($imageFilename)) {
577 $result = @unlink($this->
getImagePath() . $imageFilename);
585 if (!strlen($imageFilename)) {
589 if (!file_exists($this->
getImagePath() . $imageFilename)) {
610 public function storeImageFile(
string $upload_file,
string $upload_name): ?string
612 $name_parts = explode(
".", $upload_name);
613 $suffix = strtolower(array_pop($name_parts));
614 if (!in_array($suffix, self::VALID_UPLOAD_SUFFIXES)) {
620 $target_filepath = $this->
getImagePath() . $target_filename;
625 return $target_filename;
633 $existing_image_path = $this->
getImagePath() . $existing_image_name;
635 $target_filepath = $this->
getImagePath() . $target_filename;
641 return $target_filename;
644 return $existing_image_name;
651 if (!$submittedSolutionList->hasElements()) {
661 bool $authorized =
true 663 if ($this->questionpool_request->raw(
'test_answer_changed') ===
null) {
667 if (is_null($pass)) {
672 function () use ($active_id, $pass, $authorized) {
676 $value1 = $orderingElement->getStorageValue1($this->
getOrderingType());
677 $value2 = $orderingElement->getStorageValue2($this->
getOrderingType());
679 $this->
saveCurrentSolution($active_id, $pass, $value1, trim((
string) $value2), $authorized);
697 $this->db->manipulateF(
703 $this->db->manipulateF(
704 "INSERT INTO " . $this->
getAdditionalTableName() .
" (question_fi, ordering_type, thumb_geometry, element_height) 705 VALUES (%s, %s, %s, %s)",
706 [
"integer",
"text",
"integer",
"integer"],
709 $this->ordering_type,
734 return "assOrderingQuestion";
745 return "qpl_qst_ordering";
756 return "qpl_a_ordering";
765 $text = parent::getRTETextWithMediaObjects();
768 $text .= $orderingElement->getContent();
790 $this->element_height = ($a_height < 20) ?
null : $a_height;
800 if ($orderingElement->getContent() !==
'') {
819 switch (strtoupper($path_info[
'extension'])) {
840 $result[
'id'] = $this->
getId();
845 $result[
'shuffle'] =
true;
847 $result[
'feedback'] = [
848 'onenotcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
849 'allcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
858 $answers[$counter] = $orderingElement->getContent();
861 $answers = $this->
getShuffler()->transform($answers);
863 foreach ($answers as $order => $answer) {
865 "answertext" => (
string) $answer,
866 "order" => (
int) $order
869 $result[
'answers'] = $arr;
872 $result[
'mobs'] = $mobs;
874 return json_encode($result);
897 $formField->setInteractionEnabled(
true);
905 $formField->setEditElementOccuranceEnabled(
true);
906 $formField->setEditElementOrderEnabled(
true);
915 $formField->
setInfo($this->
lng->txt(
'ordering_answer_sequence_info'));
928 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
933 return $orderingElementInput;
945 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
948 $orderingElementInput->setImageUploadCommand(self::ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG);
949 $orderingElementInput->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
953 return $orderingElementInput;
964 $form_data_converter,
965 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
968 $ordering_element_input->setUniquePrefix($this->
getId());
970 $ordering_element_input->setElementImagePath($this->
getImagePathWeb());
975 return $ordering_element_input;
982 $ordering_gui->setValueByArray($user_solution_post);
984 if (!$ordering_gui->checkInput()) {
992 foreach ($ordering_gui->getElementList($this->getId()) as $submitted_element) {
993 $solution_element = $stored_element_list->getElementByRandomIdentifier(
994 $submitted_element->getRandomIdentifier()
997 $solution_element->setPosition($submitted_element->getPosition());
1000 $solution_element->setIndentation($submitted_element->getIndentation());
1003 $solution_ordering_element_list->addElement($solution_element);
1006 return $solution_ordering_element_list;
1013 if ($this->postSolutionOrderingElementList ===
null) {
1015 $this->
http->request()->getParsedBody()
1017 $this->postSolutionOrderingElementList = $list;
1028 $user_element = $solution_ordering_element_list->
getElementByPosition($correct_element->getPosition());
1029 if (!$correct_element->isSameElement($user_element)) {
1030 $reached_points = 0;
1035 return $reached_points;
1040 return ilOperatorsExpressionMapping::getOperatorsByExpression($expression);
1061 $data = $this->db->queryF(
1062 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s ORDER BY value1 ASC ",
1063 [
"integer",
"integer",
"integer",
"integer"],
1064 [$active_id, $pass, $this->
getId(), $maxStep]
1067 $data = $this->db->queryF(
1068 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s ORDER BY value1 ASC ",
1069 [
"integer",
"integer",
"integer"],
1070 [$active_id, $pass, $this->
getId()]
1075 while ($row = $this->db->fetchAssoc(
$data)) {
1076 $newKey = explode(
":", $row[
"value2"]);
1081 if ($answer->getSolutionIdentifier() == $row[
"value1"]) {
1082 $elements[$row[
"value2"]] = $answer->getSolutionIdentifier() + 1;
1086 if ($answer->getRandomIdentifier() == $newKey[0]) {
1087 $elements[$row[
"value1"]] = $answer->getSolutionIdentifier() + 1;
1096 foreach (array_values($elements) as $element) {
1097 $result->addKeyValue($element, $element);
1103 $result->setReachedPercentage((
$points / $max_points) * 100);
1117 if ($index !==
null) {
1134 return parent::buildTestPresentationConfig()
1137 ->setUseUnchangedAnswerLabel($this->
lng->txt(
'tst_unchanged_order_is_correct'));
1153 $solution_submit = [];
1155 if (isset($form_submission_data_structure[
'orderresult'])) {
1156 $orderresult = $form_submission_data_structure[
'orderresult'];
1158 if (strlen($orderresult)) {
1159 $orderarray = explode(
":", $orderresult);
1161 foreach ($orderarray as $index) {
1163 if (preg_match(
"/id_(\\d+)/", $index, $idmatch)) {
1164 $randomid = $idmatch[1];
1166 if ($answer->getRandomIdentifier() == $randomid) {
1167 $solution_submit[$answeridx] = $ordervalue;
1176 foreach ($form_submission_data_structure[
'content'] as $randomId => $content) {
1177 $indentation = $form_submission_data_structure[
'indentation'];
1180 $value2 = implode(
':', [$randomId, $indentation]);
1182 $solution_submit[$value1] = $value2;
1185 foreach ($form_submission_data_structure as $key => $value) {
1187 if (preg_match(
"/^order_(\d+)/", $key, $matches)) {
1188 if (!(preg_match(
"/initial_value_\d+/", $value))) {
1189 if (strlen($value)) {
1191 if ($answer->getRandomIdentifier() == $matches[1]) {
1192 $solution_submit[$answeridx] = $value;
1201 return $solution_submit;
1210 $converter->setPostVar(self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR);
1223 $formDataConverter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1225 $formDataConverter->setImageFsPath($this->
getImagePath());
1230 return $formDataConverter;
1240 return $form_data_converter;
1252 $form_data_converter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1254 $form_data_converter->setThumbnailPrefix($this->
getThumbPrefix());
1257 return $form_data_converter;
1263 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->
getQuestionType(),
1266 AdditionalInformationGenerator::KEY_QUESTION_ORDERING_NESTING_TYPE => array_reduce(
1268 static fn(
string $string,
string $lang_var) => $string . $additional_info->
getTagForLangVar($lang_var),
1271 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $this->
getPoints(),
1273 AdditionalInformationGenerator::KEY_FEEDBACK => [
1274 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
1275 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
1282 switch ($ordering_type) {
1283 case self::OQ_PICTURES:
1284 return [
'qst_nested_nested_answers_off',
'oq_btn_use_order_pictures'];
1285 case self::OQ_TERMS:
1286 return [
'qst_nested_nested_answers_off',
'oq_btn_use_order_terms'];
1287 case self::OQ_NESTED_PICTURES:
1288 return [
'qst_nested_nested_answers_on',
'oq_btn_use_order_pictures'];
1289 case self::OQ_NESTED_TERMS:
1290 return [
'qst_nested_nested_answers_on',
'oq_btn_use_order_terms'];
1302 $answers_gui->setInteractionEnabled(
false);
1303 $answers_gui->setElementList($solution_ordering_list);
1305 return $answers_gui->getHTML();
1310 array $solution_values
1312 if ($solution_values === []) {
1324 if ($solution_values === []) {
1358 $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.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
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)
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)