ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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($data["title"], $data["other"], $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 $this->saveCategoriesToDb();
139 }
140 return $affectedRows;
141 }
142
143 public function saveCategoriesToDb(): void
144 {
146
147 $affectedRows = $ilDB->manipulateF(
148 "DELETE FROM svy_variable WHERE question_fi = %s",
149 array('integer'),
150 array($this->getId())
151 );
152
153 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
154 $cat = $this->categories->getCategory($i);
155 $category_id = $this->saveCategoryToDb($cat->title, $cat->neutral);
156 $next_id = $ilDB->nextId('svy_variable');
157 $affectedRows = $ilDB->manipulateF(
158 "INSERT INTO svy_variable (variable_id, category_fi, question_fi, value1, other, sequence, scale, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
159 array('integer','integer','integer','float','integer','integer', 'integer','integer'),
160 array($next_id, $category_id, $this->getId(), ($i + 1), $cat->other, $i, ($cat->scale > 0) ? $cat->scale : null, time())
161 );
162 }
163 $this->saveCompletionStatus();
164 }
165
166 public function toXML(
167 bool $a_include_header = true,
168 bool $obligatory_state = false
169 ): string {
170 $a_xml_writer = new ilXmlWriter();
171 $a_xml_writer->xmlHeader();
172 $this->insertXML($a_xml_writer, $a_include_header);
173 $xml = $a_xml_writer->xmlDumpMem(false);
174 if (!$a_include_header) {
175 $pos = strpos($xml, "?>");
176 $xml = substr($xml, $pos + 2);
177 }
178 return $xml;
179 }
180
184 public function insertXML(
185 ilXmlWriter $a_xml_writer,
186 bool $a_include_header = true
187 ): void {
188 $attrs = array(
189 "id" => $this->getId(),
190 "title" => $this->getTitle(),
191 "type" => $this->getQuestionType(),
192 "obligatory" => $this->getObligatory()
193 );
194 $a_xml_writer->xmlStartTag("question", $attrs);
195
196 $a_xml_writer->xmlElement("description", null, $this->getDescription());
197 $a_xml_writer->xmlElement("author", null, $this->getAuthor());
198 if (strlen($this->label ?? "")) {
199 $attrs = array(
200 "label" => $this->label,
201 );
202 } else {
203 $attrs = array();
204 }
205 $a_xml_writer->xmlStartTag("questiontext", $attrs);
206 $this->addMaterialTag($a_xml_writer, $this->getQuestiontext());
207 $a_xml_writer->xmlEndTag("questiontext");
208
209 $a_xml_writer->xmlStartTag("responses");
210
211 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
212 $attrs = array(
213 "id" => $i
214 );
215 if (strlen($this->categories->getCategory($i)->other ?? "")) {
216 $attrs['other'] = $this->categories->getCategory($i)->other;
217 }
218 if (strlen($this->categories->getCategory($i)->neutral ?? "")) {
219 $attrs['neutral'] = $this->categories->getCategory($i)->neutral;
220 }
221 if (strlen($this->categories->getCategory($i)->label ?? "")) {
222 $attrs['label'] = $this->categories->getCategory($i)->label;
223 }
224 if (strlen($this->categories->getCategory($i)->scale ?? "")) {
225 $attrs['scale'] = $this->categories->getCategory($i)->scale;
226 }
227 $a_xml_writer->xmlStartTag("response_multiple", $attrs);
228 $this->addMaterialTag($a_xml_writer, $this->categories->getCategory($i)->title);
229 $a_xml_writer->xmlEndTag("response_multiple");
230 }
231
232 $a_xml_writer->xmlEndTag("responses");
233
234 if (count($this->material)) {
235 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $this->material["internal_link"], $matches)) {
236 $attrs = array(
237 "label" => $this->material["title"]
238 );
239 $a_xml_writer->xmlStartTag("material", $attrs);
240 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
241 if (strcmp($matches[1], "") !== 0) {
242 $intlink = $this->material["internal_link"];
243 }
244 $a_xml_writer->xmlElement("mattext", null, $intlink);
245 $a_xml_writer->xmlEndTag("material");
246 }
247 }
248
249 $a_xml_writer->xmlStartTag("metadata");
250 $a_xml_writer->xmlStartTag("metadatafield");
251 $a_xml_writer->xmlElement("fieldlabel", null, "orientation");
252 $a_xml_writer->xmlElement("fieldentry", null, $this->getOrientation());
253 $a_xml_writer->xmlEndTag("metadatafield");
254 $a_xml_writer->xmlStartTag("metadatafield");
255 $a_xml_writer->xmlElement("fieldlabel", null, "use_min_answers");
256 $a_xml_writer->xmlElement("fieldentry", null, $this->use_min_answers);
257 $a_xml_writer->xmlEndTag("metadatafield");
258 $a_xml_writer->xmlStartTag("metadatafield");
259 $a_xml_writer->xmlElement("fieldlabel", null, "nr_min_answers");
260 $a_xml_writer->xmlElement("fieldentry", null, $this->nr_min_answers);
261 $a_xml_writer->xmlEndTag("metadatafield");
262 $a_xml_writer->xmlStartTag("metadatafield");
263 $a_xml_writer->xmlElement("fieldlabel", null, "nr_max_answers");
264 $a_xml_writer->xmlElement("fieldentry", null, $this->nr_max_answers);
265 $a_xml_writer->xmlEndTag("metadatafield");
266 $a_xml_writer->xmlEndTag("metadata");
267
268 $a_xml_writer->xmlEndTag("question");
269 }
270
271 public function getQuestionType(): string
272 {
273 return "SurveyMultipleChoiceQuestion";
274 }
275
276 public function getAdditionalTableName(): string
277 {
278 return "svy_qst_mc";
279 }
280
281 public function getWorkingDataFromUserInput(array $post_data): array
282 {
283 $entered_value = $post_data[$this->getId() . "_value"] ?? "";
284 $data = array();
285 if (is_array($entered_value)) {
286 foreach ($entered_value as $idx => $value) {
287 $data[] = array("value" => $value,
288 "textanswer" => $post_data[$this->getId() . '_' . $value . '_other'] ?? ""
289 );
290 }
291 }
292 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
293 $cat = $this->categories->getCategory($i);
294 if ($cat->other) {
295 // #18212
296 if (!is_array($entered_value) || !in_array($i, $entered_value)) {
297 if (strlen($post_data[$this->getId() . "_" . $i . "_other"] ?? "")) {
298 $data[] = array("value" => $i,
299 "textanswer" => $post_data[$this->getId() . '_' . $i . '_other'] ?? "",
300 "uncheck" => true
301 );
302 }
303 }
304 }
305 }
306 return $data;
307 }
308
312 public function checkUserInput(
313 array $post_data,
314 int $survey_id
315 ): string {
316 $entered_value = (array) ($post_data[$this->getId() . "_value"] ?? []);
317 if (!$this->getObligatory() && (count($entered_value) === 0)) {
318 return "";
319 }
320
321 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) {
322 return sprintf($this->lng->txt("err_no_exact_answers"), $this->nr_min_answers);
323 }
324 if ($this->use_min_answers && $this->nr_min_answers > 0 && count($entered_value) < $this->nr_min_answers) {
325 return sprintf($this->lng->txt("err_no_min_answers"), $this->nr_min_answers);
326 }
327 if ($this->use_min_answers && $this->nr_max_answers > 0 && count($entered_value) > $this->nr_max_answers) {
328 return sprintf($this->lng->txt("err_no_max_answers"), $this->nr_max_answers);
329 }
330 if (count($entered_value) == 0) {
331 return $this->lng->txt("question_mr_not_checked");
332 }
333 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
334 $cat = $this->categories->getCategory($i);
335 if ($cat->other) {
336 if (in_array($i, $entered_value)) {
337 if (array_key_exists($this->getId() . "_" . $i . "_other", $post_data) && !strlen($post_data[$this->getId() . "_" . $i . "_other"] ?? "")) {
338 return $this->lng->txt("question_mr_no_other_answer");
339 }
340 } elseif (strlen($post_data[$this->getId() . "_" . $i . "_other"] ?? "")) {
341 return $this->lng->txt("question_mr_no_other_answer_checked");
342 }
343 }
344 }
345 return "";
346 }
347
348 public function saveUserInput(
349 array $post_data,
350 int $active_id,
351 bool $a_return = false
352 ): ?array {
353 $ilDB = $this->db;
354
355 if ($a_return) {
356 $return_data = array();
357 }
358 if (is_array($post_data[$this->getId() . "_value"] ?? null)) {
359 foreach ($post_data[$this->getId() . "_value"] as $entered_value) {
360 if (strlen($entered_value ?? "") > 0) {
361 if (!$a_return) {
362 $next_id = $ilDB->nextId('svy_answer');
363
364 #20216
365 $fields = array();
366 $fields['answer_id'] = array("integer", $next_id);
367 $fields['question_fi'] = array("integer", $this->getId());
368 $fields['active_fi'] = array("integer", $active_id);
369 $fields['value'] = array("float", (strlen($entered_value ?? "")) ? $entered_value : null);
370 $fields['textanswer'] = array("clob", isset($post_data[$this->getId() . "_" . $entered_value . "_other"]) ? $this->stripSlashesAddSpaceFallback($post_data[$this->getId() . "_" . $entered_value . "_other"]) : null);
371 $fields['tstamp'] = array("integer", time());
372
373 $affectedRows = $ilDB->insert("svy_answer", $fields);
374 } else {
375 $return_data[] = array("value" => $entered_value,
376 "textanswer" => $post_data[$this->getId() . "_" . $entered_value . "_other"] ?? "");
377 }
378 }
379 }
380 }
381 if ($a_return) {
382 return $return_data;
383 }
384 return null;
385 }
386
387 public function importAdditionalMetadata(array $a_meta): void
388 {
389 foreach ($a_meta as $key => $value) {
390 switch ($value["label"]) {
391 case "orientation":
392 $this->setOrientation($value["entry"]);
393 break;
394 case "use_min_answers":
395 $this->use_min_answers = $value["entry"];
396 break;
397 case "nr_min_answers":
398 $this->nr_min_answers = $value["entry"];
399 break;
400 case "nr_max_answers":
401 $this->nr_max_answers = $value["entry"];
402 break;
403 }
404 }
405 }
406
407 public function importResponses(array $a_data): void
408 {
409 foreach ($a_data as $id => $data) {
410 $categorytext = "";
411 foreach ($data["material"] as $material) {
412 $categorytext .= $material["text"];
413 }
414 $this->categories->addCategory(
415 $categorytext,
416 strlen($data['other'] ?? "") ? $data['other'] : 0,
417 strlen($data['neutral'] ?? "") ? $data['neutral'] : 0,
418 strlen($data['label'] ?? "") ? $data['label'] : null,
419 strlen($data['scale'] ?? "") ? $data['scale'] : null
420 );
421 }
422 }
423
424 public function usableForPrecondition(): bool
425 {
426 return true;
427 }
428
429 public function getAvailableRelations(): array
430 {
431 return array("=", "<>");
432 }
433
434 public function getPreconditionOptions(): array
435 {
436 $options = array();
437 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
438 $category = $this->categories->getCategory($i);
439 $options[$category->scale - 1] = $category->scale . " - " . $category->title;
440 }
441 return $options;
442 }
443
445 string $default,
446 string $title,
447 string $variable
449 $step3 = new ilSelectInputGUI($title, $variable);
450 $options = $this->getPreconditionOptions();
451 $step3->setOptions($options);
452 $step3->setValue($default);
453 return $step3;
454 }
455
457 string $value
458 ): string {
459 // #18136
460 $category = $this->categories->getCategoryForScale((int) $value + 1);
461
462 // #17895 - see getPreconditionOptions()
463 return $category->scale .
464 " - " .
465 ((strlen($category->title ?? "")) ? $category->title : $this->lng->txt('other_answer'));
466 }
467
469 {
470 return $this->categories;
471 }
472
473 public static function getMaxSumScore(int $survey_id): int
474 {
475 global $DIC;
476
477 // we need sum of scale values of multiple choice questions (type 1)
478 $db = $DIC->database();
479 $set = $db->queryF(
480 "SELECT SUM(scale) sum_sum_score FROM svy_svy_qst sq " .
481 "JOIN svy_question q ON (sq.question_fi = q.question_id) " .
482 "JOIN svy_variable v ON (v.question_fi = q.question_id) " .
483 "WHERE sq.survey_fi = %s AND q.questiontype_fi = %s ",
484 ["integer", "integer"],
485 [$survey_id, 1]
486 );
487 $rec = $db->fetchAssoc($set);
488 return (int) $rec["sum_sum_score"];
489 }
490}
$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
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26