ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.SurveyMatrixQuestion.php
Go to the documentation of this file.
1<?php
2
25{
28 // First bipolar adjective for ordinal matrix questions
29 public string $bipolar_adjective1 = "";
30 // Second bipolar adjective for ordinal matrix questions
31 public string $bipolar_adjective2 = "";
32 // Enable state of separators for matrix columns
33 public bool $columnSeparators = false;
34 // Enable state of separators for matrix rows
35 public bool $rowSeparators = false;
36 // Enable state of a separator for the neutral column
37 public bool $neutralColumnSeparator = false;
38 public array $layout;
39 // Use placeholders for the column titles
40 public bool $columnPlaceholders = false;
41 public bool $legend = false;
42 public bool $singleLineRowCaption = false;
43 public bool $repeatColumnHeader = false;
44
55 public int $subtype;
56
57 public function __construct(
58 string $title = "",
59 string $description = "",
60 string $author = "",
61 string $questiontext = "",
62 int $owner = -1
63 ) {
64 global $DIC;
65
66 $this->user = $DIC->user();
67 $this->db = $DIC->database();
69
70 $this->subtype = 0;
71 $this->columns = new SurveyCategories();
72 $this->rows = new SurveyCategories();
73 $this->bipolar_adjective1 = "";
74 $this->bipolar_adjective2 = "";
75 $this->rowSeparators = 0;
76 $this->columnSeparators = 0;
77 $this->neutralColumnSeparator = 1;
78 }
79
80 public function getColumnCount(): int
81 {
82 return $this->columns->getCategoryCount();
83 }
84
85 public function removeColumn(int $index): void
86 {
87 $this->columns->removeCategory($index);
88 }
89
93 public function removeColumns(array $array): void
94 {
95 $this->columns->removeCategories($array);
96 }
97
98 public function removeColumnWithName(string $name): void
99 {
100 $this->columns->removeCategoryWithName($name);
101 }
102
103 public function getColumns(): SurveyCategories
104 {
105 return $this->columns;
106 }
107
108 public function getColumn(int $index): ?ilSurveyCategory
109 {
110 return $this->columns->getCategory($index);
111 }
112
113 public function getColumnForScale(int $scale): ?ilSurveyCategory
114 {
115 return $this->columns->getCategoryForScale($scale);
116 }
117
118 public function getColumnIndex(string $name): int
119 {
120 return $this->columns->getCategoryIndex($name);
121 }
122
123 public function flushColumns(): void
124 {
125 $this->columns->flushCategories();
126 }
127
128 public function getRowCount(): int
129 {
130 return $this->rows->getCategoryCount();
131 }
132
133 public function addRow(
134 string $a_text,
135 string $a_other,
136 string $a_label
137 ): void {
138 $this->rows->addCategory($a_text, (int) $a_other, 0, $a_label);
139 }
140
141 public function addRowAtPosition(
142 string $a_text,
143 string $a_other,
144 int $a_position
145 ): void {
146 $this->rows->addCategoryAtPosition($a_text, $a_position, $a_other);
147 }
148
149 public function flushRows(): void
150 {
151 $this->rows = new SurveyCategories();
152 }
153
154 public function getRow(int $a_index): ?ilSurveyCategory
155 {
156 return $this->rows->getCategory($a_index);
157 }
158
159 public function moveRowUp(int $index): void
160 {
161 $this->rows->moveCategoryUp($index);
162 }
163
164 public function moveRowDown(int $index): void
165 {
166 $this->rows->moveCategoryDown($index);
167 }
168
172 public function removeRows(array $array): void
173 {
174 $this->rows->removeCategories($array);
175 }
176
177 public function removeRow(int $index): void
178 {
179 $this->rows->removeCategory($index);
180 }
181
186 public function getBipolarAdjective(int $a_index): string
187 {
188 if ($a_index === 1) {
189 return $this->bipolar_adjective2;
190 }
191 return $this->bipolar_adjective1;
192 }
193
194 public function setBipolarAdjective(
195 int $a_index,
196 string $a_value
197 ): void {
198 if ($a_index === 1) {
199 $this->bipolar_adjective2 = $a_value;
200 } else {
201 $this->bipolar_adjective1 = $a_value;
202 }
203 }
204
208 public function getQuestionDataArray(int $id): array
209 {
210 $ilDB = $this->db;
211
212 $result = $ilDB->queryF(
213 "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",
214 array('integer'),
215 array($id)
216 );
217 if ($result->numRows() === 1) {
218 return $ilDB->fetchAssoc($result);
219 }
220
221 return array();
222 }
223
224 public function loadFromDb(int $question_id): void
225 {
226 $ilDB = $this->db;
227 $result = $ilDB->queryF(
228 "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",
229 array('integer'),
230 array($question_id)
231 );
232 if ($result->numRows() === 1) {
233 $data = $ilDB->fetchAssoc($result);
234 $this->setId((int) $data["question_id"]);
235 $this->setTitle((string) $data["title"]);
236 $this->label = (string) $data['label'];
237 $this->setDescription((string) $data["description"]);
238 $this->setObjId((int) $data["obj_fi"]);
239 $this->setAuthor((string) $data["author"]);
240 $this->setOwner((int) $data["owner_fi"]);
241 $this->setQuestiontext(ilRTE::_replaceMediaObjectImageSrc((string) $data["questiontext"], 1));
242 $this->setObligatory((bool) $data["obligatory"]);
243 $this->setComplete((bool) $data["complete"]);
244 $this->setOriginalId((int) $data["original_id"]);
245 $this->setSubtype((int) $data["subtype"]);
246 $this->setRowSeparators((bool) $data["row_separators"]);
247 $this->setNeutralColumnSeparator((bool) $data["neutral_column_separator"]);
248 $this->setColumnSeparators((bool) $data["column_separators"]);
249 $this->setColumnPlaceholders((bool) $data["column_placeholders"]);
250 $this->setLegend((bool) $data["legend"]);
251 $this->setSingleLineRowCaption((string) $data["singleline_row_caption"]);
252 $this->setRepeatColumnHeader((bool) $data["repeat_column_header"]);
253 $this->setBipolarAdjective(0, (string) $data["bipolar_adjective1"]);
254 $this->setBipolarAdjective(1, (string) $data["bipolar_adjective2"]);
255 $this->setLayout($data["layout"]);
256 $this->flushColumns();
257
258 $result = $ilDB->queryF(
259 "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",
260 array('integer'),
261 array($question_id)
262 );
263 if ($result->numRows() > 0) {
264 while ($data = $ilDB->fetchAssoc($result)) {
265 $this->columns->addCategory($data["title"], (int) $data["other"], (int) $data["neutral"], null, ($data['scale']) ?: ($data['sequence'] + 1));
266 }
267 }
268
269 $result = $ilDB->queryF(
270 "SELECT * FROM svy_qst_matrixrows WHERE question_fi = %s ORDER BY sequence",
271 array('integer'),
272 array($question_id)
273 );
274 while ($row = $ilDB->fetchAssoc($result)) {
275 $this->addRow((string) $row["title"], (string) $row['other'], (string) ($row['label'] ?? ""));
276 }
277 }
278 parent::loadFromDb($question_id);
279 }
280
281 public function isComplete(): bool
282 {
283 return (
284 $this->getTitle() !== '' &&
285 $this->getAuthor() !== '' &&
286 $this->getQuestiontext() !== '' &&
287 $this->getColumnCount() &&
288 $this->getRowCount()
289 );
290 }
291
292 public function saveToDb(int $original_id = 0): int
293 {
294 $ilDB = $this->db;
295
296 $affectedRows = parent::saveToDb($original_id);
297
298 if ($affectedRows === 1) {
299 $ilDB->manipulateF(
300 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
301 array('integer'),
302 array($this->getId())
303 );
304 $ilDB->manipulateF(
305 "INSERT INTO " . $this->getAdditionalTableName() . " (
306 question_fi, subtype, column_separators, row_separators, neutral_column_separator,column_placeholders,
307 legend, singleline_row_caption, repeat_column_header,
308 bipolar_adjective1, bipolar_adjective2, layout, tstamp)
309 VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
310 array(
311 'integer', 'integer', 'text', 'text', 'text', 'integer', 'text', 'text', 'text',
312 'text', 'text', 'text', 'integer'
313 ),
314 array(
315 $this->getId(),
316 $this->getSubtype(),
317 $this->getColumnSeparators(),
318 $this->getRowSeparators(),
319 $this->getNeutralColumnSeparator(),
320 $this->getColumnPlaceholders(),
321 $this->getLegend(),
322 $this->getSingleLineRowCaption(),
323 $this->getRepeatColumnHeader(),
324 $this->getBipolarAdjective(0),
325 $this->getBipolarAdjective(1),
326 serialize($this->getLayout()),
327 time()
328 )
329 );
330
331 $this->saveColumnsToDb();
332 $this->saveRowsToDb();
333 }
334 return $affectedRows;
335 }
336
337 public function saveBipolarAdjectives(
338 string $adjective1,
339 string $adjective2
340 ): void {
341 $ilDB = $this->db;
342
343 $ilDB->manipulateF(
344 "UPDATE " . $this->getAdditionalTableName() . " SET bipolar_adjective1 = %s, bipolar_adjective2 = %s WHERE question_fi = %s",
345 array('text', 'text', 'integer'),
346 array(($adjective1 !== '') ? $adjective1 : null, ($adjective2 !== '') ? $adjective2 : null, $this->getId())
347 );
348 }
349
350 public function saveColumnToDb(
351 string $columntext,
352 int $neutral = 0
353 ): int {
354 $ilUser = $this->user;
355 $ilDB = $this->db;
356
357 $result = $ilDB->queryF(
358 "SELECT title, category_id FROM svy_category WHERE title = %s AND neutral = %s AND owner_fi = %s",
359 array('text', 'text', 'integer'),
360 array($columntext, $neutral, $ilUser->getId())
361 );
362 $insert = false;
363 $returnvalue = "";
364 $insert = true;
365 if ($result->numRows()) {
366 while ($row = $ilDB->fetchAssoc($result)) {
367 if (strcmp($row["title"] ?? '', $columntext) === 0) {
368 $returnvalue = $row["category_id"];
369 $insert = false;
370 }
371 }
372 }
373 if ($insert) {
374 $next_id = $ilDB->nextId('svy_category');
375 $affectedRows = $ilDB->manipulateF(
376 "INSERT INTO svy_category (category_id, title, defaultvalue, owner_fi, neutral, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
377 array('integer', 'text', 'text', 'integer', 'text', 'integer'),
378 array($next_id, $columntext, 0, $ilUser->getId(), $neutral, time())
379 );
380 $returnvalue = $next_id;
381 }
382 return $returnvalue;
383 }
384
385 public function saveColumnsToDb(
386 int $original_id = 0
387 ): void {
388 $ilDB = $this->db;
389
390 // save columns
391 $question_id = $this->getId();
392 if ($original_id > 0) {
393 $question_id = $original_id;
394 }
395
396 // delete existing column relations
397 $affectedRows = $ilDB->manipulateF(
398 "DELETE FROM svy_variable WHERE question_fi = %s",
399 array('integer'),
400 array($question_id)
401 );
402 // create new column relations
403 for ($i = 0; $i < $this->getColumnCount(); $i++) {
404 $cat = $this->getColumn($i);
405 $column_id = $this->saveColumnToDb($cat->title, $cat->neutral);
406 $next_id = $ilDB->nextId('svy_variable');
407 $affectedRows = $ilDB->manipulateF(
408 "INSERT INTO svy_variable (variable_id, category_fi, question_fi, value1, other, sequence, scale, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
409 array('integer','integer','integer','float','integer','integer', 'integer','integer'),
410 array($next_id, $column_id, $question_id, ($i + 1), $cat->other, $i, ($cat->scale > 0) ? $cat->scale : null, time())
411 );
412 }
413 $this->saveCompletionStatus($original_id);
414 }
415
416 public function saveRowsToDb(
417 int $original_id = 0
418 ): void {
419 $ilDB = $this->db;
420
421 // save rows
422 $question_id = $this->getId();
423 if ($original_id > 0) {
424 $question_id = $original_id;
425 }
426
427 // delete existing rows
428 $affectedRows = $ilDB->manipulateF(
429 "DELETE FROM svy_qst_matrixrows WHERE question_fi = %s",
430 array('integer'),
431 array($question_id)
432 );
433 // create new rows
434 for ($i = 0; $i < $this->getRowCount(); $i++) {
435 $row = $this->getRow($i);
436 $next_id = $ilDB->nextId('svy_qst_matrixrows');
437 $affectedRows = $ilDB->manipulateF(
438 "INSERT INTO svy_qst_matrixrows (id_svy_qst_matrixrows, title, label, other, sequence, question_fi) VALUES (%s, %s, %s, %s, %s, %s)",
439 array('integer','text','text','integer','integer','integer'),
440 array($next_id, $row->title, $row->label, ($row->other) ? 1 : 0, $i, $question_id)
441 );
442 }
443 $this->saveCompletionStatus($original_id);
444 }
445
452 public function toXML(
453 bool $a_include_header = true,
454 bool $obligatory_state = false
455 ): string {
456 $a_xml_writer = new ilXmlWriter();
457 $a_xml_writer->xmlHeader();
458 $this->insertXML($a_xml_writer, $a_include_header);
459 $xml = $a_xml_writer->xmlDumpMem(false);
460 if (!$a_include_header) {
461 $pos = strpos($xml, "?>");
462 $xml = substr($xml, $pos + 2);
463 }
464 return $xml;
465 }
466
470 public function insertXML(
471 ilXmlWriter $a_xml_writer,
472 bool $a_include_header = true
473 ): void {
474 $attrs = array(
475 "id" => $this->getId(),
476 "title" => $this->getTitle(),
477 "type" => $this->getQuestionType(),
478 "subtype" => $this->getSubtype(),
479 "obligatory" => $this->getObligatory()
480 );
481 $a_xml_writer->xmlStartTag("question", $attrs);
482
483 $a_xml_writer->xmlElement("description", null, $this->getDescription());
484 $a_xml_writer->xmlElement("author", null, $this->getAuthor());
485 $a_xml_writer->xmlStartTag("questiontext");
486 $this->addMaterialTag($a_xml_writer, $this->getQuestiontext());
487 $a_xml_writer->xmlEndTag("questiontext");
488
489 $a_xml_writer->xmlStartTag("matrix");
490 $a_xml_writer->xmlStartTag("matrixrows");
491 for ($i = 0; $i < $this->getRowCount(); $i++) {
492 $attrs = array(
493 "id" => $i
494 );
495 if (strlen($this->getRow($i)->label ?? "")) {
496 $attrs['label'] = $this->getRow($i)->label;
497 }
498 if ($this->getRow($i)->other) {
499 $attrs['other'] = 1;
500 }
501 $a_xml_writer->xmlStartTag("matrixrow", $attrs);
502 $this->addMaterialTag($a_xml_writer, $this->getRow($i)->title);
503 $a_xml_writer->xmlEndTag("matrixrow");
504 }
505 $a_xml_writer->xmlEndTag("matrixrows");
506
507 $a_xml_writer->xmlStartTag("responses");
508 if ($this->getBipolarAdjective(0) !== '' && ($this->getBipolarAdjective(1) !== '')) {
509 $a_xml_writer->xmlStartTag("bipolar_adjectives");
510 $attribs = array(
511 "label" => "0"
512 );
513 $a_xml_writer->xmlElement("adjective", $attribs, $this->getBipolarAdjective(0));
514 $attribs = array(
515 "label" => "1"
516 );
517 $a_xml_writer->xmlElement("adjective", $attribs, $this->getBipolarAdjective(1));
518 $a_xml_writer->xmlEndTag("bipolar_adjectives");
519 }
520 for ($i = 0; $i < $this->getColumnCount(); $i++) {
521 $attrs = array(
522 "id" => $i
523 );
524 if ($this->getColumn($i)->neutral) {
525 $attrs['label'] = 'neutral';
526 }
527 switch ($this->getSubtype()) {
528 case 0:
529 $a_xml_writer->xmlStartTag("response_single", $attrs);
530 break;
531 case 1:
532 $a_xml_writer->xmlStartTag("response_multiple", $attrs);
533 break;
534 }
535 $this->addMaterialTag($a_xml_writer, $this->getColumn($i)->title);
536 switch ($this->getSubtype()) {
537 case 0:
538 $a_xml_writer->xmlEndTag("response_single");
539 break;
540 case 1:
541 $a_xml_writer->xmlEndTag("response_multiple");
542 break;
543 }
544 }
545
546 $a_xml_writer->xmlEndTag("responses");
547 $a_xml_writer->xmlEndTag("matrix");
548
549 if (count($this->material)) {
550 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $this->material["internal_link"], $matches)) {
551 $attrs = array(
552 "label" => $this->material["title"]
553 );
554 $a_xml_writer->xmlStartTag("material", $attrs);
555 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
556 if (strcmp($matches[1], "") !== 0) {
557 $intlink = $this->material["internal_link"];
558 }
559 $a_xml_writer->xmlElement("mattext", null, $intlink);
560 $a_xml_writer->xmlEndTag("material");
561 }
562 }
563
564 $a_xml_writer->xmlStartTag("metadata");
565 $a_xml_writer->xmlStartTag("metadatafield");
566 $a_xml_writer->xmlElement("fieldlabel", null, "column_separators");
567 $a_xml_writer->xmlElement("fieldentry", null, $this->getColumnSeparators());
568 $a_xml_writer->xmlEndTag("metadatafield");
569
570 $a_xml_writer->xmlStartTag("metadatafield");
571 $a_xml_writer->xmlElement("fieldlabel", null, "row_separators");
572 $a_xml_writer->xmlElement("fieldentry", null, $this->getRowSeparators());
573 $a_xml_writer->xmlEndTag("metadatafield");
574
575 $a_xml_writer->xmlStartTag("metadatafield");
576 $a_xml_writer->xmlElement("fieldlabel", null, "neutral_column_separator");
577 $a_xml_writer->xmlElement("fieldentry", null, $this->getNeutralColumnSeparator());
578 $a_xml_writer->xmlEndTag("metadatafield");
579
580 $a_xml_writer->xmlStartTag("metadatafield");
581 $a_xml_writer->xmlElement("fieldlabel", null, "layout");
582 $a_xml_writer->xmlElement("fieldentry", null, serialize($this->getLayout()));
583 $a_xml_writer->xmlEndTag("metadatafield");
584
585 $a_xml_writer->xmlEndTag("metadata");
586
587 $a_xml_writer->xmlEndTag("question");
588 }
589
590 public function syncWithOriginal(): void
591 {
592 if ($this->getOriginalId()) {
593 parent::syncWithOriginal();
594 $this->saveColumnsToDb($this->getOriginalId());
595 $this->saveRowsToDb($this->getOriginalId());
596 }
597 }
598
602 public function addStandardNumbers(
603 int $lower_limit,
604 int $upper_limit
605 ): void {
606 for ($i = $lower_limit; $i <= $upper_limit; $i++) {
607 $this->columns->addCategory($i);
608 }
609 }
610
611
612 public function getQuestionType(): string
613 {
614 return "SurveyMatrixQuestion";
615 }
616
620 public function getAdditionalTableName(): string
621 {
622 return "svy_qst_matrix";
623 }
624
625 public function getWorkingDataFromUserInput(array $post_data): array
626 {
627 $data = array();
628 foreach ($post_data as $key => $value) {
629 switch ($this->getSubtype()) {
630 case 1:
631 case 0:
632 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
633 if (is_array($value)) {
634 foreach ($value as $val) {
635 $data[] = array("value" => $val,
636 "rowvalue" => $matches[1],
637 "textanswer" => $post_data['matrix_other_' . $this->getId(
638 ) . '_' . $matches[1]] ?? ""
639 );
640 }
641 } else {
642 $data[] = array("value" => $value,
643 "rowvalue" => $matches[1],
644 "textanswer" => $post_data['matrix_other_' . $this->getId(
645 ) . '_' . $matches[1]] ?? ""
646 );
647 }
648 }
649 break;
650 }
651 }
652 return $data;
653 }
654
660 public function checkUserInput(
661 array $post_data,
662 int $survey_id
663 ): string {
664 if (!$this->getObligatory()) {
665 return "";
666 }
667 switch ($this->getSubtype()) {
668 case 0:
669 $counter = 0;
670 foreach ($post_data as $key => $value) {
671 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
672 if (array_key_exists('matrix_other_' . $this->getId() . "_" . $matches[1], $post_data) && strlen($post_data['matrix_other_' . $this->getId() . "_" . $matches[1]] ?? "") == 0) {
673 return $this->lng->txt("question_mr_no_other_answer");
674 }
675 $counter++;
676 }
677 }
678 if ($counter !== $this->getRowCount()) {
679 return $this->lng->txt("matrix_question_radio_button_not_checked");
680 }
681 break;
682 case 1:
683 $counter = 0;
684 foreach ($post_data as $key => $value) {
685 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
686 if (array_key_exists('matrix_other_' . $this->getId() . "_" . $matches[1], $post_data) && strlen($post_data['matrix_other_' . $this->getId() . "_" . $matches[1]] ?? "") == 0) {
687 return $this->lng->txt("question_mr_no_other_answer");
688 }
689 $counter++;
690 if ((!is_array($value)) || (count($value) < 1)) {
691 return $this->lng->txt("matrix_question_checkbox_not_checked");
692 }
693 }
694 }
695 if ($counter !== $this->getRowCount()) {
696 return $this->lng->txt("matrix_question_checkbox_not_checked");
697 }
698 break;
699 }
700 return "";
701 }
702
703 public function saveUserInput(
704 array $post_data,
705 int $active_id,
706 bool $a_return = false
707 ): ?array {
708 $ilDB = $this->db;
709
710 $answer_data = array();
711
712 // gather data
713 switch ($this->getSubtype()) {
714 case 0:
715 foreach ($post_data as $key => $value) {
716 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
717 if (strlen($value ?? "")) {
718 $other_value = (array_key_exists('matrix_other_' . $this->getId() . '_' . $matches[1], $post_data))
719 ? $this->stripSlashesAddSpaceFallback($post_data['matrix_other_' . $this->getId() . '_' . $matches[1]])
720 : null;
721 $answer_data[] = array("value" => $value,
722 "textanswer" => $other_value,
723 "rowvalue" => $matches[1]);
724 }
725 }
726 }
727 break;
728
729 case 1:
730 foreach ($post_data as $key => $value) {
731 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
732 $other_value = (array_key_exists('matrix_other_' . $this->getId() . '_' . $matches[1], $post_data))
733 ? $this->stripSlashesAddSpaceFallback($post_data['matrix_other_' . $this->getId() . '_' . $matches[1]])
734 : null;
735 foreach ($value as $checked) {
736 $answer_data[] = array("value" => $checked,
737 "textanswer" => $other_value,
738 "rowvalue" => $matches[1]);
739 }
740 }
741 }
742 break;
743 }
744
745 if ($a_return) {
746 return $answer_data;
747 }
748
749 // #16387 - only if any input
750 if (count($answer_data)) {
751 // save data
752 foreach ($answer_data as $item) {
753 $next_id = $ilDB->nextId('svy_answer');
754 #20216
755 $fields = array();
756 $fields['answer_id'] = array("integer", $next_id);
757 $fields['question_fi'] = array("integer", $this->getId());
758 $fields['active_fi'] = array("integer", $active_id);
759 $fields['value'] = array("float", $item['value']);
760 $fields['textanswer'] = array("clob", $item['textanswer']);
761 $fields['rowvalue'] = array("integer", $item['rowvalue']);
762 $fields['tstamp'] = array("integer", time());
763
764 $affectedRows = $ilDB->insert("svy_answer", $fields);
765 }
766 }
767 return null;
768 }
769
774 int $question_id
775 ): void {
776 parent::deleteAdditionalTableData($question_id);
777
778 $ilDB = $this->db;
779 $ilDB->manipulateF(
780 "DELETE FROM svy_qst_matrixrows WHERE question_fi = %s",
781 array('integer'),
782 array($question_id)
783 );
784 }
785
789 public function getSubtype(): ?int
790 {
791 return $this->subtype;
792 }
793
797 public function setSubtype(int $a_subtype = 0): void
798 {
799 switch ($a_subtype) {
800 case 1:
801 case 2:
802 case 3:
803 case 4:
804 case 5:
805 case 6:
806 $this->subtype = $a_subtype;
807 break;
808 case 0:
809 default:
810 $this->subtype = 0;
811 break;
812 }
813 }
814
818 public function setColumnSeparators(bool $enable = false): void
819 {
820 $this->columnSeparators = $enable;
821 }
822
823 public function getColumnSeparators(): bool
824 {
825 return $this->columnSeparators;
826 }
827
831 public function setRowSeparators(bool $enable = false): void
832 {
833 $this->rowSeparators = $enable;
834 }
835
836 public function getRowSeparators(): bool
837 {
838 return $this->rowSeparators;
839 }
840
841 public function setNeutralColumnSeparator(bool $enable = true): void
842 {
843 $this->neutralColumnSeparator = $enable;
844 }
845
846 public function getNeutralColumnSeparator(): bool
847 {
848 return $this->neutralColumnSeparator;
849 }
850
854 public function importAdditionalMetadata(array $a_meta): void
855 {
856 foreach ($a_meta as $key => $value) {
857 switch ($value["label"]) {
858 case "column_separators":
859 $this->setColumnSeparators($value["entry"]);
860 break;
861 case "row_separators":
862 $this->setRowSeparators($value["entry"]);
863 break;
864 case "layout":
865 $this->setLayout($value["entry"]);
866 break;
867 case "neutral_column_separator":
868 $this->setNeutralColumnSeparator($value["entry"]);
869 break;
870 }
871 }
872 }
873
877 public function importAdjectives(array $a_data): void
878 {
879 $i = 0;
880 foreach ($a_data as $adjective) {
881 if (is_numeric($adjective["label"])) {
882 $this->setBipolarAdjective($adjective["label"], $adjective["text"]);
883 } else {
884 $this->setBipolarAdjective($i, $adjective["text"]);
885 }
886 $i++;
887 }
888 }
889
893 public function importMatrix(
894 array $a_data
895 ): void {
896 foreach ($a_data as $row) {
897 $this->addRow($row['title'], $row['other'], $row['label']);
898 }
899 }
900
904 public function importResponses(array $a_data): void
905 {
906 foreach ($a_data as $id => $data) {
907 $column = "";
908 foreach ($data["material"] as $material) {
909 $column .= $material["text"];
910 }
911 $this->columns->addCategory($column, 0, strcmp($data["label"], "neutral") == 0);
912 }
913 }
914
918 public function usableForPrecondition(): bool
919 {
920 return false;
921 }
922
926 public function getPreconditionValueOutput(string $value): string
927 {
928 return $value;
929 }
930
935 string $default,
936 string $title,
937 string $variable
939 $step3 = new ilSelectInputGUI($title, $variable);
940 $options = $this->getPreconditionOptions();
941 $step3->setOptions($options);
942 $step3->setValue($default);
943 return $step3;
944 }
945
955 public function saveLayout(
956 float $percent_row,
957 float $percent_columns,
958 float $percent_bipolar_adjective1 = 0,
959 float $percent_bipolar_adjective2 = 0,
960 float $percent_neutral = 0
961 ): void {
962 $ilDB = $this->db;
963
964 $layout = array(
965 "percent_row" => $percent_row,
966 "percent_columns" => $percent_columns,
967 "percent_bipolar_adjective1" => $percent_bipolar_adjective1,
968 "percent_bipolar_adjective2" => $percent_bipolar_adjective2,
969 "percent_neutral" => $percent_neutral
970 );
971 $affectedRows = $ilDB->manipulateF(
972 "UPDATE " . $this->getAdditionalTableName() . " SET layout = %s WHERE question_fi = %s",
973 array('text', 'integer'),
974 array(serialize($layout), $this->getId())
975 );
976 }
977
978 public function getLayout(): array
979 {
980 if (count($this->layout) === 0) {
981 if ($this->hasBipolarAdjectives() && $this->hasNeutralColumn()) {
982 $this->layout = array(
983 "percent_row" => 30,
984 "percent_columns" => 40,
985 "percent_bipolar_adjective1" => 10,
986 "percent_bipolar_adjective2" => 10,
987 "percent_neutral" => 10
988 );
989 } elseif ($this->hasBipolarAdjectives()) {
990 $this->layout = array(
991 "percent_row" => 30,
992 "percent_columns" => 50,
993 "percent_bipolar_adjective1" => 10,
994 "percent_bipolar_adjective2" => 10,
995 "percent_neutral" => 0
996 );
997 } elseif ($this->hasNeutralColumn()) {
998 $this->layout = array(
999 "percent_row" => 30,
1000 "percent_columns" => 50,
1001 "percent_bipolar_adjective1" => 0,
1002 "percent_bipolar_adjective2" => 0,
1003 "percent_neutral" => 20
1004 );
1005 } else {
1006 $this->layout = array(
1007 "percent_row" => 30,
1008 "percent_columns" => 70,
1009 "percent_bipolar_adjective1" => 0,
1010 "percent_bipolar_adjective2" => 0,
1011 "percent_neutral" => 0
1012 );
1013 }
1014 }
1015 return $this->layout;
1016 }
1017
1021 public function setLayout($layout): void
1022 {
1023 if (is_array($layout)) {
1024 $this->layout = $layout;
1025 } else {
1026 $this->layout = unserialize((string) $layout, ['allowed_classes' => false]) ?: [];
1027 }
1028 }
1029
1033 public function hasBipolarAdjectives(): bool
1034 {
1035 return $this->getBipolarAdjective(0) !== '' && $this->getBipolarAdjective(1) !== '';
1036 }
1037
1041 public function hasNeutralColumn(): bool
1042 {
1043 for ($i = 0; $i < $this->getColumnCount(); $i++) {
1044 $column = $this->getColumn($i);
1045 if ($column->neutral && strlen($column->title ?? "")) {
1046 return true;
1047 }
1048 }
1049 return false;
1050 }
1051
1055 public function setColumnPlaceholders(bool $a_value = false): void
1056 {
1057 $this->columnPlaceholders = $a_value;
1058 }
1059
1060 public function getColumnPlaceholders(): bool
1061 {
1062 return $this->columnPlaceholders;
1063 }
1064
1068 public function setLegend(bool $a_value = false): void
1069 {
1070 $this->legend = $a_value;
1071 }
1072
1073 public function getLegend(): bool
1074 {
1075 return $this->legend;
1076 }
1077
1078 public function setSingleLineRowCaption(bool $a_value = false): void
1079 {
1080 $this->singleLineRowCaption = $a_value;
1081 }
1082
1083 public function getSingleLineRowCaption(): bool
1084 {
1085 return $this->singleLineRowCaption;
1086 }
1087
1088 public function setRepeatColumnHeader(bool $a_value = false): void
1089 {
1090 $this->repeatColumnHeader = $a_value;
1091 }
1092
1093 public function getRepeatColumnHeader(): bool
1094 {
1095 return $this->repeatColumnHeader;
1096 }
1097
1098
1099 public function getRows(): SurveyCategories
1100 {
1101 return $this->rows;
1102 }
1103
1104 public static function getMaxSumScore(int $survey_id): int
1105 {
1106 global $DIC;
1107
1108 // we need max scale values of matrix rows * number of rows (type 5)
1109 $db = $DIC->database();
1110
1111 $set = $db->queryF(
1112 "SELECT MAX(scale) max_sum_score, q.question_id FROM svy_svy_qst sq " .
1113 "JOIN svy_question q ON (sq.question_fi = q.question_id) " .
1114 "JOIN svy_variable v ON (v.question_fi = q.question_id) " .
1115 "WHERE sq.survey_fi = %s AND q.questiontype_fi = %s " .
1116 "GROUP BY (q.question_id)",
1117 ["integer", "integer"],
1118 [$survey_id, 5]
1119 );
1120 $max_score = [];
1121 while ($rec = $db->fetchAssoc($set)) {
1122 $max_score[$rec["question_id"]] = $rec["max_sum_score"];
1123 }
1124
1125 $set = $db->queryF(
1126 "SELECT COUNT(mr.id_svy_qst_matrixrows) cnt_rows, q.question_id FROM svy_svy_qst sq " .
1127 "JOIN svy_question q ON (sq.question_fi = q.question_id) " .
1128 "JOIN svy_qst_matrixrows mr ON (mr.question_fi = q.question_id) " .
1129 "WHERE sq.survey_fi = %s AND q.questiontype_fi = %s " .
1130 "GROUP BY (q.question_id)",
1131 ["integer", "integer"],
1132 [$survey_id, 5]
1133 );
1134 $cnt_rows = [];
1135 while ($rec = $db->fetchAssoc($set)) {
1136 $cnt_rows[$rec["question_id"]] = $rec["cnt_rows"];
1137 }
1138
1139 $sum_sum_score = 0;
1140 foreach ($max_score as $qid => $s) {
1141 $sum_sum_score += $s * $cnt_rows[$qid];
1142 }
1143
1144 return $sum_sum_score;
1145 }
1146}
$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...
setRepeatColumnHeader(bool $a_value=false)
hasNeutralColumn()
Returns TRUE if a neutral column exists.
int $subtype
Matrix question subtype 0 = Single choice 1 = Multiple choice 2 = Text 3 = Integer 4 = Double 5 = Dat...
__construct(string $title="", string $description="", string $author="", string $questiontext="", int $owner=-1)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
importAdjectives(array $a_data)
Import bipolar adjectives from the question import file.
setBipolarAdjective(int $a_index, string $a_value)
setLegend(bool $a_value=false)
Set whether the legend should be shown or not.
getWorkingDataFromUserInput(array $post_data)
Creates the user data of the svy_answer table from the POST data.
saveColumnsToDb(int $original_id=0)
getPreconditionSelectValue(string $default, string $title, string $variable)
Creates a form property for the precondition value.
getQuestionDataArray(int $id)
Returns the question data fields from the database.
setRowSeparators(bool $enable=false)
Enables/Disables separators for the matrix rows.
setColumnSeparators(bool $enable=false)
Enables/Disables separators for the matrix columns.
getSubtype()
Returns the subtype of the matrix question.
toXML(bool $a_include_header=true, bool $obligatory_state=false)
Returns an xml representation of the question.
saveToDb(int $original_id=0)
Saves a SurveyQuestion object to a database.
saveColumnToDb(string $columntext, int $neutral=0)
setSingleLineRowCaption(bool $a_value=false)
importResponses(array $a_data)
Import response data from the question import file.
addRow(string $a_text, string $a_other, string $a_label)
usableForPrecondition()
Returns if the question is usable for preconditions.
checkUserInput(array $post_data, int $survey_id)
Checks the input of the active user for obligatory status and entered values.
saveBipolarAdjectives(string $adjective1, string $adjective2)
saveUserInput(array $post_data, int $active_id, bool $a_return=false)
insertXML(ilXmlWriter $a_xml_writer, bool $a_include_header=true)
Adds the question XML to a given XMLWriter object.
importAdditionalMetadata(array $a_meta)
Import additional meta data from the question import file.
loadFromDb(int $question_id)
load question data into object note: this base implementation only loads the material data
addStandardNumbers(int $lower_limit, int $upper_limit)
Adds standard numbers as columns.
getBipolarAdjective(int $a_index)
Returns one of the bipolar adjectives.
importMatrix(array $a_data)
Import matrix rows from the question import file.
hasBipolarAdjectives()
Returns TRUE if bipolar adjectives exist.
getPreconditionValueOutput(string $value)
Returns the output for a precondition value.
setColumnPlaceholders(bool $a_value=false)
Set whether placeholders should be used for the column titles or not.
deleteAdditionalTableData(int $question_id)
Delete question data from additional table.
saveLayout(float $percent_row, float $percent_columns, float $percent_bipolar_adjective1=0, float $percent_bipolar_adjective2=0, float $percent_neutral=0)
Saves the layout of a matrix question.
static getMaxSumScore(int $survey_id)
Get max sum score for specific survey (and this question type)
setSubtype(int $a_subtype=0)
Sets the subtype of the matrix question.
addRowAtPosition(string $a_text, string $a_other, int $a_position)
setNeutralColumnSeparator(bool $enable=true)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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...
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
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
$counter