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);
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]
526 if (preg_match(
"/.*\\.(\\w+)$/",
$filename, $matches)) {
527 $extension = $matches[1];
529 return md5(
$filename) .
"." . $extension;
537 foreach ($contents as
$f) {
538 if (strcmp($f[
'type'],
'file') == 0) {
541 if (strcmp($f[
'entry'], $orderElement->getContent()) == 0) {
544 if (strcmp($f[
'entry'], $this->
getThumbPrefix() . $orderElement->getContent()) == 0) {
549 if (@file_exists($this->
getImagePath() . $f[
'entry'])) {
571 if (!strlen($imageFilename)) {
575 $result = @unlink($this->
getImagePath() . $imageFilename);
583 if (!strlen($imageFilename)) {
587 if (!file_exists($this->
getImagePath() . $imageFilename)) {
608 public function storeImageFile(
string $upload_file,
string $upload_name): ?string
610 $name_parts = explode(
".", $upload_name);
611 $suffix = strtolower(array_pop($name_parts));
612 if (!in_array($suffix, self::VALID_UPLOAD_SUFFIXES)) {
618 $target_filepath = $this->
getImagePath() . $target_filename;
623 return $target_filename;
631 $existing_image_path = $this->
getImagePath() . $existing_image_name;
633 $target_filepath = $this->
getImagePath() . $target_filename;
639 return $target_filename;
642 return $existing_image_name;
649 if (!$submittedSolutionList->hasElements()) {
659 bool $authorized =
true 661 if ($this->questionpool_request->raw(
'test_answer_changed') ===
null) {
665 if (is_null($pass)) {
670 function () use ($active_id, $pass, $authorized) {
674 $value1 = $orderingElement->getStorageValue1($this->
getOrderingType());
675 $value2 = $orderingElement->getStorageValue2($this->
getOrderingType());
677 $this->
saveCurrentSolution($active_id, $pass, $value1, trim((
string) $value2), $authorized);
695 $this->db->manipulateF(
701 $this->db->manipulateF(
702 "INSERT INTO " . $this->
getAdditionalTableName() .
" (question_fi, ordering_type, thumb_geometry, element_height) 703 VALUES (%s, %s, %s, %s)",
704 [
"integer",
"text",
"integer",
"integer"],
707 $this->ordering_type,
732 return "assOrderingQuestion";
743 return "qpl_qst_ordering";
754 return "qpl_a_ordering";
763 $text = parent::getRTETextWithMediaObjects();
766 $text .= $orderingElement->getContent();
788 $this->element_height = ($a_height < 20) ?
null : $a_height;
798 if ($orderingElement->getContent() !==
'') {
817 switch (strtoupper($path_info[
'extension'])) {
838 $result[
'id'] = $this->
getId();
843 $result[
'shuffle'] =
true;
845 $result[
'feedback'] = [
846 'onenotcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
847 'allcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
856 $answers[$counter] = $orderingElement->getContent();
859 $answers = $this->
getShuffler()->transform($answers);
861 foreach ($answers as $order => $answer) {
863 "answertext" => (
string) $answer,
864 "order" => (
int) $order
867 $result[
'answers'] = $arr;
870 $result[
'mobs'] = $mobs;
872 return json_encode($result);
895 $formField->setInteractionEnabled(
true);
903 $formField->setEditElementOccuranceEnabled(
true);
904 $formField->setEditElementOrderEnabled(
true);
913 $formField->
setInfo($this->
lng->txt(
'ordering_answer_sequence_info'));
926 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
930 $orderingElementInput->setInfo($orderingElementInput->getInfo() .
' ' . $this->
lng->txt(
'latex_edit_info'));
932 return $orderingElementInput;
944 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
947 $orderingElementInput->setImageUploadCommand(self::ORDERING_ELEMENT_FORM_CMD_UPLOAD_IMG);
948 $orderingElementInput->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
952 return $orderingElementInput;
963 $form_data_converter,
964 self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR
967 $ordering_element_input->setUniquePrefix($this->
getId());
969 $ordering_element_input->setElementImagePath($this->
getImagePathWeb());
974 return $ordering_element_input;
981 $ordering_gui->setValueByArray($user_solution_post);
983 if (!$ordering_gui->checkInput()) {
991 foreach ($ordering_gui->getElementList($this->getId()) as $submitted_element) {
992 $solution_element = $stored_element_list->getElementByRandomIdentifier(
993 $submitted_element->getRandomIdentifier()
996 $solution_element->setPosition($submitted_element->getPosition());
999 $solution_element->setIndentation($submitted_element->getIndentation());
1002 $solution_ordering_element_list->addElement($solution_element);
1005 return $solution_ordering_element_list;
1012 if ($this->postSolutionOrderingElementList ===
null) {
1014 $this->
http->request()->getParsedBody()
1016 $this->postSolutionOrderingElementList = $list;
1027 $user_element = $solution_ordering_element_list->
getElementByPosition($correct_element->getPosition());
1028 if (!$correct_element->isSameElement($user_element)) {
1029 $reached_points = 0;
1034 return $reached_points;
1039 return ilOperatorsExpressionMapping::getOperatorsByExpression($expression);
1060 $data = $this->db->queryF(
1061 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s ORDER BY value1 ASC ",
1062 [
"integer",
"integer",
"integer",
"integer"],
1063 [$active_id, $pass, $this->
getId(), $maxStep]
1066 $data = $this->db->queryF(
1067 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s ORDER BY value1 ASC ",
1068 [
"integer",
"integer",
"integer"],
1069 [$active_id, $pass, $this->
getId()]
1074 while ($row = $this->db->fetchAssoc(
$data)) {
1075 $newKey = explode(
":", $row[
"value2"]);
1080 if ($answer->getSolutionIdentifier() == $row[
"value1"]) {
1081 $elements[$row[
"value2"]] = $answer->getSolutionIdentifier() + 1;
1085 if ($answer->getRandomIdentifier() == $newKey[0]) {
1086 $elements[$row[
"value1"]] = $answer->getSolutionIdentifier() + 1;
1095 foreach (array_values($elements) as $element) {
1096 $result->addKeyValue($element, $element);
1102 $result->setReachedPercentage((
$points / $max_points) * 100);
1116 if ($index !==
null) {
1133 return parent::buildTestPresentationConfig()
1136 ->setUseUnchangedAnswerLabel($this->
lng->txt(
'tst_unchanged_order_is_correct'));
1152 $solution_submit = [];
1154 if (isset($form_submission_data_structure[
'orderresult'])) {
1155 $orderresult = $form_submission_data_structure[
'orderresult'];
1157 if (strlen($orderresult)) {
1158 $orderarray = explode(
":", $orderresult);
1160 foreach ($orderarray as $index) {
1162 if (preg_match(
"/id_(\\d+)/", $index, $idmatch)) {
1163 $randomid = $idmatch[1];
1165 if ($answer->getRandomIdentifier() == $randomid) {
1166 $solution_submit[$answeridx] = $ordervalue;
1175 foreach ($form_submission_data_structure[
'content'] as $randomId => $content) {
1176 $indentation = $form_submission_data_structure[
'indentation'];
1179 $value2 = implode(
':', [$randomId, $indentation]);
1181 $solution_submit[$value1] = $value2;
1184 foreach ($form_submission_data_structure as $key => $value) {
1186 if (preg_match(
"/^order_(\d+)/", $key, $matches)) {
1187 if (!(preg_match(
"/initial_value_\d+/", $value))) {
1188 if (strlen($value)) {
1190 if ($answer->getRandomIdentifier() == $matches[1]) {
1191 $solution_submit[$answeridx] = $value;
1200 return $solution_submit;
1209 $converter->setPostVar(self::ORDERING_ELEMENT_FORM_FIELD_POSTVAR);
1222 $formDataConverter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1224 $formDataConverter->setImageFsPath($this->
getImagePath());
1229 return $formDataConverter;
1239 return $form_data_converter;
1251 $form_data_converter->setImageRemovalCommand(self::ORDERING_ELEMENT_FORM_CMD_REMOVE_IMG);
1253 $form_data_converter->setThumbnailPrefix($this->
getThumbPrefix());
1256 return $form_data_converter;
1262 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->
getQuestionType(),
1265 AdditionalInformationGenerator::KEY_QUESTION_ORDERING_NESTING_TYPE => array_reduce(
1267 static fn(
string $string,
string $lang_var) => $string . $additional_info->
getTagForLangVar($lang_var),
1270 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $this->
getPoints(),
1272 AdditionalInformationGenerator::KEY_FEEDBACK => [
1273 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
1274 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
1281 switch ($ordering_type) {
1282 case self::OQ_PICTURES:
1283 return [
'qst_nested_nested_answers_off',
'oq_btn_use_order_pictures'];
1284 case self::OQ_TERMS:
1285 return [
'qst_nested_nested_answers_off',
'oq_btn_use_order_terms'];
1286 case self::OQ_NESTED_PICTURES:
1287 return [
'qst_nested_nested_answers_on',
'oq_btn_use_order_pictures'];
1288 case self::OQ_NESTED_TERMS:
1289 return [
'qst_nested_nested_answers_on',
'oq_btn_use_order_terms'];
1301 $answers_gui->setInteractionEnabled(
false);
1302 $answers_gui->setElementList($solution_ordering_list);
1304 return $answers_gui->getHTML();
1309 array $solution_values
1311 if ($solution_values === []) {
1323 if ($solution_values === []) {
1357 $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.
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)