ILIAS  release_8 Revision v8.24
class.SurveySingleChoiceQuestion.php
Go to the documentation of this file.
1<?php
2
28{
30
31 public function __construct(
32 string $title = "",
33 string $description = "",
34 string $author = "",
35 string $questiontext = "",
36 int $owner = -1,
37 int $orientation = 1
38 ) {
39 global $DIC;
40
41 $this->db = $DIC->database();
42 $this->user = $DIC->user();
43 $this->lng = $DIC->language();
45
46 $this->orientation = $orientation;
47 $this->categories = new SurveyCategories();
48 }
49
53 public function getCategoriesForPhrase(int $phrase_id): array
54 {
56 $categories = array();
57 $result = $ilDB->queryF(
58 "SELECT svy_category.* FROM svy_category, svy_phrase_cat WHERE svy_phrase_cat.category_fi = svy_category.category_id AND svy_phrase_cat.phrase_fi = %s ORDER BY svy_phrase_cat.sequence",
59 array('integer'),
60 array($phrase_id)
61 );
62 while ($row = $ilDB->fetchAssoc($result)) {
63 if ((int) $row["defaultvalue"] === 1 && (int) $row["owner_fi"] === 0) {
64 $categories[$row["category_id"]] = $this->lng->txt($row["title"]);
65 } else {
66 $categories[$row["category_id"]] = $row["title"];
67 }
68 }
69 return $categories;
70 }
71
75 public function addPhrase(int $phrase_id): void
76 {
79
80 $result = $ilDB->queryF(
81 "SELECT svy_category.* FROM svy_category, svy_phrase_cat WHERE svy_phrase_cat.category_fi = svy_category.category_id AND svy_phrase_cat.phrase_fi = %s AND (svy_category.owner_fi = 0 OR svy_category.owner_fi = %s) ORDER BY svy_phrase_cat.sequence",
82 array('integer', 'integer'),
83 array($phrase_id, $ilUser->getId())
84 );
85 while ($row = $ilDB->fetchAssoc($result)) {
86 $neutral = $row["neutral"];
87 if ((int) $row["defaultvalue"] === 1 && (int) $row["owner_fi"] === 0) {
88 $this->categories->addCategory($this->lng->txt($row["title"]), 0, $neutral);
89 } else {
90 $this->categories->addCategory($row["title"], 0, $neutral);
91 }
92 }
93 }
94
95 public function getQuestionDataArray(int $id): array
96 {
98
99 $result = $ilDB->queryF(
100 "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",
101 array('integer'),
102 array($id)
103 );
104 if ($result->numRows() === 1) {
105 return $ilDB->fetchAssoc($result);
106 } else {
107 return array();
108 }
109 }
110
111 public function loadFromDb(int $question_id): void
112 {
114
115 $result = $ilDB->queryF(
116 "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",
117 array('integer'),
118 array($question_id)
119 );
120 if ($result->numRows() === 1) {
121 $data = $ilDB->fetchAssoc($result);
122 $this->setId((int) $data["question_id"]);
123 $this->setTitle((string) $data["title"]);
124 $this->label = (string) $data['label'];
125 $this->setDescription((string) $data["description"]);
126 $this->setObjId((int) $data["obj_fi"]);
127 $this->setAuthor((string) $data["author"]);
128 $this->setOwner((int) $data["owner_fi"]);
129 $this->setQuestiontext(ilRTE::_replaceMediaObjectImageSrc((string) $data["questiontext"], 1));
130 $this->setObligatory((bool) $data["obligatory"]);
131 $this->setComplete((bool) $data["complete"]);
132 $this->setOriginalId((int) $data["original_id"]);
133 $this->setOrientation((int) $data["orientation"]);
134
135 $this->categories->flushCategories();
136 $result = $ilDB->queryF(
137 "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",
138 array('integer'),
139 array($question_id)
140 );
141 if ($result->numRows() > 0) {
142 while ($data = $ilDB->fetchAssoc($result)) {
143 $this->categories->addCategory((string) $data["title"], (int) $data["other"], (int) $data["neutral"], null, ($data['scale']) ?: ($data['sequence'] + 1));
144 }
145 }
146 }
147 parent::loadFromDb($question_id);
148 }
149
150 public function isComplete(): bool
151 {
152 if (
153 $this->getTitle() !== '' &&
154 $this->getAuthor() !== '' &&
155 $this->getQuestiontext() !== '' &&
156 $this->categories->getCategoryCount()
157 ) {
158 return true;
159 } else {
160 return false;
161 }
162 }
163
164 public function saveToDb(int $original_id = 0): int
165 {
167
168 $affectedRows = parent::saveToDb($original_id);
169 if ($affectedRows === 1) {
170 $this->log->debug("Before save Category-> DELETE from svy_qst_sc WHERE question_fi = " . $this->getId() . " AND INSERT again the same id and orientation in svy_qst_sc");
171 $ilDB->manipulateF(
172 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
173 array('integer'),
174 array($this->getId())
175 );
176 $ilDB->manipulateF(
177 "INSERT INTO " . $this->getAdditionalTableName() . " (question_fi, orientation) VALUES (%s, %s)",
178 array('integer', 'text'),
179 array(
180 $this->getId(),
181 $this->getOrientation()
182 )
183 );
184
185 $this->saveMaterial();
186 $this->saveCategoriesToDb();
187 }
188 return $affectedRows;
189 }
190
191 public function saveCategoriesToDb(): void
192 {
194
195 $this->log->debug("DELETE from svy_variable before the INSERT into svy_variable. if scale > 0 we get scale value else we get null");
196
197 $affectedRows = $ilDB->manipulateF(
198 "DELETE FROM svy_variable WHERE question_fi = %s",
199 array('integer'),
200 array($this->getId())
201 );
202
203 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
204 $cat = $this->categories->getCategory($i);
205 $category_id = $this->saveCategoryToDb($cat->title, $cat->neutral);
206 $next_id = $ilDB->nextId('svy_variable');
207 $affectedRows = $ilDB->manipulateF(
208 "INSERT INTO svy_variable (variable_id, category_fi, question_fi, value1, other, sequence, scale, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
209 array('integer','integer','integer','float','integer','integer', 'integer','integer'),
210 array($next_id, $category_id, $this->getId(), ($i + 1), $cat->other, $i, ($cat->scale > 0) ? $cat->scale : null, time())
211 );
212
213 $debug_scale = ($cat->scale > 0) ? $cat->scale : null;
214 $this->log->debug("INSERT INTO svy_variable category_fi= " . $category_id . " question_fi= " . $this->getId() . " value1= " . ($i + 1) . " other= " . $cat->other . " sequence= " . $i . " scale =" . $debug_scale);
215 }
216 $this->saveCompletionStatus();
217 }
218
219 public function toXML(
220 bool $a_include_header = true,
221 bool $obligatory_state = false
222 ): string {
223 $a_xml_writer = new ilXmlWriter();
224 $a_xml_writer->xmlHeader();
225 $this->insertXML($a_xml_writer, $a_include_header);
226 $xml = $a_xml_writer->xmlDumpMem(false);
227 if (!$a_include_header) {
228 $pos = strpos($xml, "?>");
229 $xml = substr($xml, $pos + 2);
230 }
231 return $xml;
232 }
233
234 public function insertXML(
235 ilXmlWriter $a_xml_writer,
236 bool $a_include_header = true
237 ): void {
238 $attrs = array(
239 "id" => $this->getId(),
240 "title" => $this->getTitle(),
241 "type" => $this->getQuestionType(),
242 "obligatory" => $this->getObligatory()
243 );
244 $a_xml_writer->xmlStartTag("question", $attrs);
245
246 $a_xml_writer->xmlElement("description", null, $this->getDescription());
247 $a_xml_writer->xmlElement("author", null, $this->getAuthor());
248 if (strlen($this->label)) {
249 $attrs = array(
250 "label" => $this->label,
251 );
252 } else {
253 $attrs = array();
254 }
255 $a_xml_writer->xmlStartTag("questiontext", $attrs);
256 $this->addMaterialTag($a_xml_writer, $this->getQuestiontext());
257 $a_xml_writer->xmlEndTag("questiontext");
258
259 $a_xml_writer->xmlStartTag("responses");
260
261 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
262 $attrs = array(
263 "id" => $i
264 );
265 if (strlen($this->categories->getCategory($i)->other)) {
266 $attrs['other'] = $this->categories->getCategory($i)->other;
267 }
268 if (strlen($this->categories->getCategory($i)->neutral)) {
269 $attrs['neutral'] = $this->categories->getCategory($i)->neutral;
270 }
271 if (strlen($this->categories->getCategory($i)->label)) {
272 $attrs['label'] = $this->categories->getCategory($i)->label;
273 }
274 if (strlen($this->categories->getCategory($i)->scale)) {
275 $attrs['scale'] = $this->categories->getCategory($i)->scale;
276 }
277 $a_xml_writer->xmlStartTag("response_single", $attrs);
278 $this->addMaterialTag($a_xml_writer, $this->categories->getCategory($i)->title);
279 $a_xml_writer->xmlEndTag("response_single");
280 }
281
282 $a_xml_writer->xmlEndTag("responses");
283
284 if (count($this->material)) {
285 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $this->material["internal_link"] ?? "", $matches)) {
286 $attrs = array(
287 "label" => $this->material["title"]
288 );
289 $a_xml_writer->xmlStartTag("material", $attrs);
290 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
291 if (strcmp($matches[1], "") != 0) {
292 $intlink = $this->material["internal_link"];
293 }
294 $a_xml_writer->xmlElement("mattext", null, $intlink);
295 $a_xml_writer->xmlEndTag("material");
296 }
297 }
298
299 $a_xml_writer->xmlStartTag("metadata");
300 $a_xml_writer->xmlStartTag("metadatafield");
301 $a_xml_writer->xmlElement("fieldlabel", null, "orientation");
302 $a_xml_writer->xmlElement("fieldentry", null, $this->getOrientation());
303 $a_xml_writer->xmlEndTag("metadatafield");
304 $a_xml_writer->xmlEndTag("metadata");
305
306 $a_xml_writer->xmlEndTag("question");
307 }
308
309 public function importAdditionalMetadata(array $a_meta): void
310 {
311 foreach ($a_meta as $key => $value) {
312 switch ($value["label"]) {
313 case "orientation":
314 $this->setOrientation($value["entry"]);
315 break;
316 }
317 }
318 }
319
323 public function addStandardNumbers(
324 int $lower_limit,
325 int $upper_limit
326 ): void {
327 for ($i = $lower_limit; $i <= $upper_limit; $i++) {
328 $this->categories->addCategory($i);
329 }
330 }
331
336 public function savePhrase(string $title): void
337 {
338 $ilUser = $this->user;
339 $ilDB = $this->db;
340
341 $next_id = $ilDB->nextId('svy_phrase');
342 $affectedRows = $ilDB->manipulateF(
343 "INSERT INTO svy_phrase (phrase_id, title, defaultvalue, owner_fi, tstamp) VALUES (%s, %s, %s, %s, %s)",
344 array('integer','text','text','integer','integer'),
345 array($next_id, $title, 1, $ilUser->getId(), time())
346 );
347 $phrase_id = $next_id;
348
349 $counter = 1;
350 $phrase_data = $this->edit_manager->getPhraseData();
351 foreach ($phrase_data as $data) {
352 $next_id = $ilDB->nextId('svy_category');
353 $affectedRows = $ilDB->manipulateF(
354 "INSERT INTO svy_category (category_id, title, defaultvalue, owner_fi, tstamp, neutral) VALUES (%s, %s, %s, %s, %s, %s)",
355 array('integer','text','text','integer','integer','text'),
356 array($next_id, $data['answer'], 1, $ilUser->getId(), time(), $data['neutral'])
357 );
358 $category_id = $next_id;
359 $next_id = $ilDB->nextId('svy_phrase_cat');
360 $affectedRows = $ilDB->manipulateF(
361 "INSERT INTO svy_phrase_cat (phrase_category_id, phrase_fi, category_fi, sequence, other, scale) VALUES (%s, %s, %s, %s, %s, %s)",
362 array('integer', 'integer', 'integer','integer', 'integer', 'integer'),
363 array($next_id, $phrase_id, $category_id, $counter, ($data['other']) ? 1 : 0, $data['scale'])
364 );
365 $counter++;
366 }
367 }
368
369 public function getQuestionType(): string
370 {
371 return "SurveySingleChoiceQuestion";
372 }
373
374 public function getAdditionalTableName(): string
375 {
376 return "svy_qst_sc";
377 }
378
380 array $post_data
381 ): array {
382 $entered_value = $post_data[$this->getId() . "_value"] ?? "";
383 $data = array();
384 if (strlen($entered_value)) {
385 $data[] = array("value" => $entered_value,
386 "textanswer" => $post_data[$this->getId() . '_' . $entered_value . '_other'] ?? ""
387 );
388 }
389 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
390 $cat = $this->categories->getCategory($i);
391 if ($cat->other) {
392 if ($i != $entered_value) {
393 if (strlen($post_data[$this->getId() . "_" . $i . "_other"] ?? "")) {
394 $data[] = array("value" => $i,
395 "textanswer" => $post_data[$this->getId() . '_' . $i . '_other'] ?? "",
396 "uncheck" => true
397 );
398 }
399 }
400 }
401 }
402 return $data;
403 }
404
409 public function checkUserInput(
410 array $post_data,
411 int $survey_id
412 ): string {
413 $entered_value = $post_data[$this->getId() . "_value"] ?? "";
414
415 $this->log->debug("Entered value = " . $entered_value);
416
417 if ((!$this->getObligatory()) && (strlen($entered_value) == 0)) {
418 return "";
419 }
420
421 if (strlen($entered_value) == 0) {
422 return $this->lng->txt("question_not_checked");
423 }
424
425 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
426 $cat = $this->categories->getCategory($i);
427 if ($cat->other) {
428 if ($i == $entered_value) {
429 if (array_key_exists($this->getId() . "_" . $entered_value . "_other", $post_data) && !strlen($post_data[$this->getId() . "_" . $entered_value . "_other"])) {
430 return $this->lng->txt("question_mr_no_other_answer");
431 }
432 } elseif (strlen($post_data[$this->getId() . "_" . $i . "_other"] ?? "")) {
433 return $this->lng->txt("question_sr_no_other_answer_checked");
434 }
435 }
436 }
437
438 return "";
439 }
440
441 public function saveUserInput(
442 array $post_data,
443 int $active_id,
444 bool $a_return = false
445 ): ?array {
446 $ilDB = $this->db;
447
448 $entered_value = $post_data[$this->getId() . "_value"] ?? "";
449
450 if ($a_return) {
451 return array(array("value" => $entered_value,
452 "textanswer" => $post_data[$this->getId() . "_" . $entered_value . "_other"] ?? ""));
453 }
454 if (strlen($entered_value) == 0) {
455 return null;
456 }
457
458 $next_id = $ilDB->nextId('svy_answer');
459 #20216
460 $fields = array();
461 $fields['answer_id'] = array("integer", $next_id);
462 $fields['question_fi'] = array("integer", $this->getId());
463 $fields['active_fi'] = array("integer", $active_id);
464 $fields['value'] = array("float", (strlen($entered_value)) ? $entered_value : null);
465 $fields['textanswer'] = array("clob", isset($post_data[$this->getId() . "_" . $entered_value . "_other"]) ?
466 $this->stripSlashesAddSpaceFallback($post_data[$this->getId() . "_" . $entered_value . "_other"]) : null);
467 $fields['tstamp'] = array("integer", time());
468
469 $affectedRows = $ilDB->insert("svy_answer", $fields);
470
471 $debug_value = (strlen($entered_value)) ? $entered_value : "NULL";
472 $debug_answer = $post_data[$this->getId() . "_" . $entered_value . "_other"] ?? "NULL";
473 $this->log->debug("INSERT svy_answer answer_id=" . $next_id . " question_fi=" . $this->getId() . " active_fi=" . $active_id . " value=" . $debug_value . " textanswer=" . $debug_answer);
474 return null;
475 }
476
477 public function importResponses(array $a_data): void
478 {
479 foreach ($a_data as $id => $data) {
480 $categorytext = "";
481 foreach ($data["material"] as $material) {
482 $categorytext .= $material["text"];
483 }
484 $this->categories->addCategory(
485 $categorytext,
486 strlen($data['other']) ? $data['other'] : 0,
487 strlen($data['neutral']) ? $data['neutral'] : 0,
488 strlen($data['label']) ? $data['label'] : null,
489 strlen($data['scale']) ? $data['scale'] : null
490 );
491 }
492 }
493
494 public function usableForPrecondition(): bool
495 {
496 return true;
497 }
498
499 public function getAvailableRelations(): array
500 {
501 return array("<", "<=", "=", "<>", ">=", ">");
502 }
503
504 public function getPreconditionOptions(): array
505 {
506 $options = array();
507 for ($i = 0; $i < $this->categories->getCategoryCount(); $i++) {
508 $category = $this->categories->getCategory($i);
509 $options[$category->scale - 1] = $category->scale . " - " . $category->title;
510 }
511 return $options;
512 }
513
515 string $default,
516 string $title,
517 string $variable
519 $step3 = new ilSelectInputGUI($title, $variable);
520 $options = $this->getPreconditionOptions();
521 $step3->setOptions($options);
522 $step3->setValue($default);
523 return $step3;
524 }
525
527 string $value
528 ): string {
529 // #18136
530 $category = $this->categories->getCategoryForScale((int) $value + 1);
531
532 $scale = "";
533 $title = "";
534 if ($category) {
535 $scale = $category->scale;
536 $title = $category->title;
537 }
538
539 // #17895 - see getPreconditionOptions()
540 return $scale .
541 " - " .
542 ((strlen($title)) ? $title : $this->lng->txt('other_answer'));
543 }
544
546 {
547 return $this->categories;
548 }
549
550 public static function getMaxSumScore(int $survey_id): int
551 {
552 global $DIC;
553
554 // we need max scale values of single choice questions (type 2)
555 $db = $DIC->database();
556 $set = $db->queryF(
557 "SELECT SUM(max_sum_score) sum_sum_score FROM (SELECT MAX(scale) max_sum_score FROM svy_svy_qst sq " .
558 "JOIN svy_question q ON (sq.question_fi = q.question_id) " .
559 "JOIN svy_variable v ON (v.question_fi = q.question_id) " .
560 "WHERE sq.survey_fi = %s AND q.questiontype_fi = %s " .
561 "GROUP BY (q.question_id)) x",
562 ["integer", "integer"],
563 [$survey_id, 2]
564 );
565 $rec = $db->fetchAssoc($set);
566 return (int) $rec["sum_sum_score"];
567 }
568
569 protected function isSumScoreValid(int $nr_answer_records): bool
570 {
571 if ($nr_answer_records == 1) {
572 return true;
573 }
574 return false;
575 }
576
577 public static function compressable(
578 int $id1,
579 int $id2
580 ): bool {
582 $q1 = SurveyQuestion::_instanciateQuestion($id1);
585 if ($q1->getOrientation() !== 1 || $q2->getOrientation() !== 1) {
586 return false;
587 }
588 if (self::getCompressCompareString($q1) === self::getCompressCompareString($q2)) {
589 return true;
590 }
591 return false;
592 }
593
594 public static function getCompressCompareString(
596 ): string {
597 $str = "";
598 for ($i = 0; $i < $q->categories->getCategoryCount(); $i++) {
599 $cat = $q->categories->getCategory($i);
600 $str .= ":" . $cat->scale . ":" . $cat->title;
601 }
602 return $str;
603 }
604}
$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...
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)
static _instanciateQuestion(int $question_id)
Get question object.
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 file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
insertXML(ilXmlWriter $a_xml_writer, bool $a_include_header=true)
savePhrase(string $title)
Saves a set of categories to a default phrase note: data comes from session.
saveToDb(int $original_id=0)
Saves a SurveyQuestion object to a database.
saveUserInput(array $post_data, int $active_id, bool $a_return=false)
getPreconditionOptions()
Returns the options for preconditions.
checkUserInput(array $post_data, int $survey_id)
Checks the input of the active user for obligatory status and entered values.
loadFromDb(int $question_id)
load question data into object note: this base implementation only loads the material data
__construct(string $title="", string $description="", string $author="", string $questiontext="", int $owner=-1, int $orientation=1)
getQuestionDataArray(int $id)
Returns the question data.
usableForPrecondition()
Returns if the question is usable for preconditions.
importResponses(array $a_data)
Import response data from the question import file.
static getCompressCompareString(SurveySingleChoiceQuestion $q)
addPhrase(int $phrase_id)
Adds a phrase to the question.
getCategoriesForPhrase(int $phrase_id)
Gets the available categories for a given phrase.
getPreconditionValueOutput(string $value)
Returns the output for a precondition value.
getPreconditionSelectValue(string $default, string $title, string $variable)
Creates a form property for the precondition value.
getAvailableRelations()
Returns the available relations for the question.
toXML(bool $a_include_header=true, bool $obligatory_state=false)
importAdditionalMetadata(array $a_meta)
Import additional meta data from the question import file.
addStandardNumbers(int $lower_limit, int $upper_limit)
Adds standard numbers as categories.
getWorkingDataFromUserInput(array $post_data)
Creates the user data of the svy_answer table from the POST data.
static getMaxSumScore(int $survey_id)
Get max sum score for specific survey (and this question type)
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
$ilUser
Definition: imgupload.php:34
$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