ILIAS  release_8 Revision v8.24
class.SurveyMultipleChoiceQuestion.php
Go to the documentation of this file.
1<?php
2
26{
28
29 public function __construct(
30 string $title = "",
31 string $description = "",
32 string $author = "",
33 string $questiontext = "",
34 int $owner = -1,
35 int $orientation = 0
36 ) {
37 global $DIC;
38
39 $this->db = $DIC->database();
40 $this->lng = $DIC->language();
42
43 $this->orientation = $orientation;
44 $this->categories = new SurveyCategories();
45 }
46
47 public function getQuestionDataArray(int $id): array
48 {
50
51 $result = $ilDB->queryF(
52 "SELECT svy_question.*, " . $this->getAdditionalTableName() . ".* FROM svy_question, " . $this->getAdditionalTableName() . " WHERE svy_question.question_id = %s AND svy_question.question_id = " . $this->getAdditionalTableName() . ".question_fi",
53 array('integer'),
54 array($id)
55 );
56 if ($result->numRows() === 1) {
57 return $ilDB->fetchAssoc($result);
58 }
59
60 return array();
61 }
62
63 public function loadFromDb(int $question_id): void
64 {
66
67 $result = $ilDB->queryF(
68 "SELECT svy_question.*, " . $this->getAdditionalTableName() . ".* FROM svy_question LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = svy_question.question_id WHERE svy_question.question_id = %s",
69 array('integer'),
70 array($question_id)
71 );
72 if ($result->numRows() === 1) {
73 $data = $ilDB->fetchAssoc($result);
74 $this->setId($data["question_id"]);
75 $this->setTitle((string) $data["title"]);
76 $this->label = (string) $data['label'];
77 $this->setDescription((string) $data["description"]);
78 $this->setObjId((int) $data["obj_fi"]);
79 $this->setAuthor((string) $data["author"]);
80 $this->setOwner((int) $data["owner_fi"]);
81 $this->setQuestiontext(ilRTE::_replaceMediaObjectImageSrc((string) $data["questiontext"], 1));
82 $this->setObligatory((bool) $data["obligatory"]);
83 $this->setComplete((bool) $data["complete"]);
84 $this->setOriginalId((int) $data["original_id"]);
85 $this->setOrientation((int) $data["orientation"]);
86 $this->use_min_answers = (bool) $data['use_min_answers'];
87 $this->nr_min_answers = (string) $data['nr_min_answers'];
88 $this->nr_max_answers = (string) $data['nr_max_answers'];
89
90 $this->categories->flushCategories();
91 $result = $ilDB->queryF(
92 "SELECT svy_variable.*, svy_category.title, svy_category.neutral FROM svy_variable, svy_category WHERE svy_variable.question_fi = %s AND svy_variable.category_fi = svy_category.category_id ORDER BY sequence ASC",
93 array('integer'),
94 array($question_id)
95 );
96 if ($result->numRows() > 0) {
97 while ($data = $ilDB->fetchAssoc($result)) {
98 $this->categories->addCategory((string) $data["title"], (int) $data["other"], (int) $data["neutral"], null, ($data['scale']) ?: ($data['sequence'] + 1));
99 }
100 }
101 }
102 parent::loadFromDb($question_id);
103 }
104
105 public function isComplete(): bool
106 {
107 return (
108 $this->getTitle() !== '' &&
109 $this->getAuthor() !== '' &&
110 $this->getQuestiontext() !== '' &&
111 $this->categories->getCategoryCount()
112 );
113 }
114
115 public function saveToDb(int $original_id = 0): int
116 {
118
119 $affectedRows = parent::saveToDb($original_id);
120 if ($affectedRows === 1) {
121 $ilDB->manipulateF(
122 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
123 array('integer'),
124 array($this->getId())
125 );
126 $ilDB->manipulateF(
127 "INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, orientation, use_min_answers, nr_min_answers, nr_max_answers) VALUES (%s, %s, %s, %s, %s)",
128 array('integer', 'text', 'integer', 'integer', 'integer'),
129 array(
130 $this->getId(),
131 $this->getOrientation(),
132 ($this->use_min_answers) ? 1 : 0,
133 ($this->nr_min_answers > 0) ? $this->nr_min_answers : null,
134 ($this->nr_max_answers > 0) ? $this->nr_max_answers : null
135 )
136 );
137
138 // saving material uris in the database
139 $this->saveMaterial();
140 $this->saveCategoriesToDb();
141 }
142 return $affectedRows;
143 }
144
145 public function saveCategoriesToDb(): void
146 {
148
149 $affectedRows = $ilDB->manipulateF(
150 "DELETE FROM svy_variable WHERE question_fi = %s",
151 array('integer'),
152 array($this->getId())
153 );
154
155 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
156 $cat = $this->categories->getCategory($i);
157 $category_id = $this->saveCategoryToDb($cat->title, $cat->neutral);
158 $next_id = $ilDB->nextId('svy_variable');
159 $affectedRows = $ilDB->manipulateF(
160 "INSERT INTO svy_variable (variable_id, category_fi, question_fi, value1, other, sequence, scale, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
161 array('integer','integer','integer','float','integer','integer', 'integer','integer'),
162 array($next_id, $category_id, $this->getId(), ($i + 1), $cat->other, $i, ($cat->scale > 0) ? $cat->scale : null, time())
163 );
164 }
165 $this->saveCompletionStatus();
166 }
167
168 public function toXML(
169 bool $a_include_header = true,
170 bool $obligatory_state = false
171 ): string {
172 $a_xml_writer = new ilXmlWriter();
173 $a_xml_writer->xmlHeader();
174 $this->insertXML($a_xml_writer, $a_include_header);
175 $xml = $a_xml_writer->xmlDumpMem(false);
176 if (!$a_include_header) {
177 $pos = strpos($xml, "?>");
178 $xml = substr($xml, $pos + 2);
179 }
180 return $xml;
181 }
182
186 public function insertXML(
187 ilXmlWriter $a_xml_writer,
188 bool $a_include_header = true
189 ): void {
190 $attrs = array(
191 "id" => $this->getId(),
192 "title" => $this->getTitle(),
193 "type" => $this->getQuestionType(),
194 "obligatory" => $this->getObligatory()
195 );
196 $a_xml_writer->xmlStartTag("question", $attrs);
197
198 $a_xml_writer->xmlElement("description", null, $this->getDescription());
199 $a_xml_writer->xmlElement("author", null, $this->getAuthor());
200 if (strlen($this->label)) {
201 $attrs = array(
202 "label" => $this->label,
203 );
204 } else {
205 $attrs = array();
206 }
207 $a_xml_writer->xmlStartTag("questiontext", $attrs);
208 $this->addMaterialTag($a_xml_writer, $this->getQuestiontext());
209 $a_xml_writer->xmlEndTag("questiontext");
210
211 $a_xml_writer->xmlStartTag("responses");
212
213 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
214 $attrs = array(
215 "id" => $i
216 );
217 if (strlen($this->categories->getCategory($i)->other)) {
218 $attrs['other'] = $this->categories->getCategory($i)->other;
219 }
220 if (strlen($this->categories->getCategory($i)->neutral)) {
221 $attrs['neutral'] = $this->categories->getCategory($i)->neutral;
222 }
223 if (strlen($this->categories->getCategory($i)->label)) {
224 $attrs['label'] = $this->categories->getCategory($i)->label;
225 }
226 if (strlen($this->categories->getCategory($i)->scale)) {
227 $attrs['scale'] = $this->categories->getCategory($i)->scale;
228 }
229 $a_xml_writer->xmlStartTag("response_multiple", $attrs);
230 $this->addMaterialTag($a_xml_writer, $this->categories->getCategory($i)->title);
231 $a_xml_writer->xmlEndTag("response_multiple");
232 }
233
234 $a_xml_writer->xmlEndTag("responses");
235
236 if (count($this->material)) {
237 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $this->material["internal_link"], $matches)) {
238 $attrs = array(
239 "label" => $this->material["title"]
240 );
241 $a_xml_writer->xmlStartTag("material", $attrs);
242 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
243 if (strcmp($matches[1], "") !== 0) {
244 $intlink = $this->material["internal_link"];
245 }
246 $a_xml_writer->xmlElement("mattext", null, $intlink);
247 $a_xml_writer->xmlEndTag("material");
248 }
249 }
250
251 $a_xml_writer->xmlStartTag("metadata");
252 $a_xml_writer->xmlStartTag("metadatafield");
253 $a_xml_writer->xmlElement("fieldlabel", null, "orientation");
254 $a_xml_writer->xmlElement("fieldentry", null, $this->getOrientation());
255 $a_xml_writer->xmlEndTag("metadatafield");
256 $a_xml_writer->xmlStartTag("metadatafield");
257 $a_xml_writer->xmlElement("fieldlabel", null, "use_min_answers");
258 $a_xml_writer->xmlElement("fieldentry", null, $this->use_min_answers);
259 $a_xml_writer->xmlEndTag("metadatafield");
260 $a_xml_writer->xmlStartTag("metadatafield");
261 $a_xml_writer->xmlElement("fieldlabel", null, "nr_min_answers");
262 $a_xml_writer->xmlElement("fieldentry", null, $this->nr_min_answers);
263 $a_xml_writer->xmlEndTag("metadatafield");
264 $a_xml_writer->xmlStartTag("metadatafield");
265 $a_xml_writer->xmlElement("fieldlabel", null, "nr_max_answers");
266 $a_xml_writer->xmlElement("fieldentry", null, $this->nr_max_answers);
267 $a_xml_writer->xmlEndTag("metadatafield");
268 $a_xml_writer->xmlEndTag("metadata");
269
270 $a_xml_writer->xmlEndTag("question");
271 }
272
273 public function getQuestionType(): string
274 {
275 return "SurveyMultipleChoiceQuestion";
276 }
277
278 public function getAdditionalTableName(): string
279 {
280 return "svy_qst_mc";
281 }
282
283 public function getWorkingDataFromUserInput(array $post_data): array
284 {
285 $entered_value = $post_data[$this->getId() . "_value"] ?? "";
286 $data = array();
287 if (is_array($entered_value)) {
288 foreach ($entered_value as $idx => $value) {
289 $data[] = array("value" => $value,
290 "textanswer" => $post_data[$this->getId() . '_' . $value . '_other'] ?? ""
291 );
292 }
293 }
294 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
295 $cat = $this->categories->getCategory($i);
296 if ($cat->other) {
297 // #18212
298 if (!is_array($entered_value) || !in_array($i, $entered_value)) {
299 if (strlen($post_data[$this->getId() . "_" . $i . "_other"])) {
300 $data[] = array("value" => $i,
301 "textanswer" => $post_data[$this->getId() . '_' . $i . '_other'] ?? "",
302 "uncheck" => true
303 );
304 }
305 }
306 }
307 }
308 return $data;
309 }
310
314 public function checkUserInput(
315 array $post_data,
316 int $survey_id
317 ): string {
318 $entered_value = (array) ($post_data[$this->getId() . "_value"] ?? []);
319 if (!$this->getObligatory() && (count($entered_value) === 0)) {
320 return "";
321 }
322
323 if ($this->use_min_answers && $this->nr_min_answers > 0 && $this->nr_max_answers > 0 && $this->nr_min_answers == $this->nr_max_answers && count($entered_value) !== (int) $this->nr_max_answers) {
324 return sprintf($this->lng->txt("err_no_exact_answers"), $this->nr_min_answers);
325 }
326 if ($this->use_min_answers && $this->nr_min_answers > 0 && count($entered_value) < $this->nr_min_answers) {
327 return sprintf($this->lng->txt("err_no_min_answers"), $this->nr_min_answers);
328 }
329 if ($this->use_min_answers && $this->nr_max_answers > 0 && count($entered_value) > $this->nr_max_answers) {
330 return sprintf($this->lng->txt("err_no_max_answers"), $this->nr_max_answers);
331 }
332 if (count($entered_value) == 0) {
333 return $this->lng->txt("question_mr_not_checked");
334 }
335 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
336 $cat = $this->categories->getCategory($i);
337 if ($cat->other) {
338 if (in_array($i, $entered_value)) {
339 if (array_key_exists($this->getId() . "_" . $i . "_other", $post_data) && !strlen($post_data[$this->getId() . "_" . $i . "_other"])) {
340 return $this->lng->txt("question_mr_no_other_answer");
341 }
342 } elseif (strlen($post_data[$this->getId() . "_" . $i . "_other"] ?? "")) {
343 return $this->lng->txt("question_mr_no_other_answer_checked");
344 }
345 }
346 }
347 return "";
348 }
349
350 public function saveUserInput(
351 array $post_data,
352 int $active_id,
353 bool $a_return = false
354 ): ?array {
355 $ilDB = $this->db;
356
357 if ($a_return) {
358 $return_data = array();
359 }
360 if (is_array($post_data[$this->getId() . "_value"] ?? null)) {
361 foreach ($post_data[$this->getId() . "_value"] as $entered_value) {
362 if (strlen($entered_value) > 0) {
363 if (!$a_return) {
364 $next_id = $ilDB->nextId('svy_answer');
365
366 #20216
367 $fields = array();
368 $fields['answer_id'] = array("integer", $next_id);
369 $fields['question_fi'] = array("integer", $this->getId());
370 $fields['active_fi'] = array("integer", $active_id);
371 $fields['value'] = array("float", (strlen($entered_value)) ? $entered_value : null);
372 $fields['textanswer'] = array("clob", isset($post_data[$this->getId() . "_" . $entered_value . "_other"]) ? $this->stripSlashesAddSpaceFallback($post_data[$this->getId() . "_" . $entered_value . "_other"]) : null);
373 $fields['tstamp'] = array("integer", time());
374
375 $affectedRows = $ilDB->insert("svy_answer", $fields);
376 } else {
377 $return_data[] = array("value" => $entered_value,
378 "textanswer" => $post_data[$this->getId() . "_" . $entered_value . "_other"] ?? "");
379 }
380 }
381 }
382 }
383 if ($a_return) {
384 return $return_data;
385 }
386 return null;
387 }
388
389 public function importAdditionalMetadata(array $a_meta): void
390 {
391 foreach ($a_meta as $key => $value) {
392 switch ($value["label"]) {
393 case "orientation":
394 $this->setOrientation($value["entry"]);
395 break;
396 case "use_min_answers":
397 $this->use_min_answers = $value["entry"];
398 break;
399 case "nr_min_answers":
400 $this->nr_min_answers = $value["entry"];
401 break;
402 case "nr_max_answers":
403 $this->nr_max_answers = $value["entry"];
404 break;
405 }
406 }
407 }
408
409 public function importResponses(array $a_data): void
410 {
411 foreach ($a_data as $id => $data) {
412 $categorytext = "";
413 foreach ($data["material"] as $material) {
414 $categorytext .= $material["text"];
415 }
416 $this->categories->addCategory(
417 $categorytext,
418 strlen($data['other']) ? $data['other'] : 0,
419 strlen($data['neutral']) ? $data['neutral'] : 0,
420 strlen($data['label']) ? $data['label'] : null,
421 strlen($data['scale']) ? $data['scale'] : null
422 );
423 }
424 }
425
426 public function usableForPrecondition(): bool
427 {
428 return true;
429 }
430
431 public function getAvailableRelations(): array
432 {
433 return array("=", "<>");
434 }
435
436 public function getPreconditionOptions(): array
437 {
438 $options = array();
439 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
440 $category = $this->categories->getCategory($i);
441 $options[$category->scale - 1] = $category->scale . " - " . $category->title;
442 }
443 return $options;
444 }
445
447 string $default,
448 string $title,
449 string $variable
451 $step3 = new ilSelectInputGUI($title, $variable);
452 $options = $this->getPreconditionOptions();
453 $step3->setOptions($options);
454 $step3->setValue($default);
455 return $step3;
456 }
457
459 string $value
460 ): string {
461 // #18136
462 $category = $this->categories->getCategoryForScale((int) $value + 1);
463
464 // #17895 - see getPreconditionOptions()
465 return $category->scale .
466 " - " .
467 ((strlen($category->title)) ? $category->title : $this->lng->txt('other_answer'));
468 }
469
471 {
472 return $this->categories;
473 }
474
475 public static function getMaxSumScore(int $survey_id): int
476 {
477 global $DIC;
478
479 // we need sum of scale values of multiple choice questions (type 1)
480 $db = $DIC->database();
481 $set = $db->queryF(
482 "SELECT SUM(scale) sum_sum_score FROM svy_svy_qst sq " .
483 "JOIN svy_question q ON (sq.question_fi = q.question_id) " .
484 "JOIN svy_variable v ON (v.question_fi = q.question_id) " .
485 "WHERE sq.survey_fi = %s AND q.questiontype_fi = %s ",
486 ["integer", "integer"],
487 [$survey_id, 1]
488 );
489 $rec = $db->fetchAssoc($set);
490 return (int) $rec["sum_sum_score"];
491 }
492}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
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...
loadFromDb(int $question_id)
load question data into object note: this base implementation only loads the material data
insertXML(ilXmlWriter $a_xml_writer, bool $a_include_header=true)
Adds the question XML to a given XMLWriter object.
getAvailableRelations()
Returns the available relations for the question.
importResponses(array $a_data)
Import response data from the question import file.
__construct(string $title="", string $description="", string $author="", string $questiontext="", int $owner=-1, int $orientation=0)
getPreconditionValueOutput(string $value)
Returns the output for a precondition value.
static getMaxSumScore(int $survey_id)
Get max sum score for specific survey (and this question type)
saveUserInput(array $post_data, int $active_id, bool $a_return=false)
usableForPrecondition()
Returns if the question is usable for preconditions.
importAdditionalMetadata(array $a_meta)
Import additional meta data from the question import file.
getWorkingDataFromUserInput(array $post_data)
Creates the user data of the svy_answer table from the POST data.
checkUserInput(array $post_data, int $survey_id)
toXML(bool $a_include_header=true, bool $obligatory_state=false)
getQuestionDataArray(int $id)
Returns the question data.
saveToDb(int $original_id=0)
Saves a SurveyQuestion object to a database.
getPreconditionOptions()
Returns the options for preconditions.
getPreconditionSelectValue(string $default, string $title, string $variable)
Creates a form property for the precondition value.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setTitle(string $title="")
saveCategoryToDb(string $categorytext, int $neutral=0)
Saves a category to the database.
setQuestiontext(string $questiontext="")
setDescription(string $description="")
setObjId(int $obj_id=0)
Set the reference(?) id of the container object.
setOrientation(int $orientation=0)
setOwner(int $owner=0)
setComplete(bool $a_complete)
setOriginalId(?int $original_id)
saveCompletionStatus(int $original_id=0)
Saves the complete flag to the database.
setObligatory(bool $obligatory=true)
setAuthor(string $author="")
This class represents a property in a property form.
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...
This class represents a selection list property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
xmlHeader()
Writes xml header.
xmlEndTag(string $tag)
Writes an endtag.
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
const IL_INST_ID
Definition: constants.php:40
global $DIC
Definition: feed.php:28
$i
Definition: metadata.php:41
$xml
Definition: metadata.php:351
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
string $key
Consumer key/client ID value.
Definition: System.php:193