ILIAS  release_8 Revision v8.24
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 addPhrase(int $phrase_id): void
209 {
210 $ilUser = $this->user;
211 $ilDB = $this->db;
212
213 $result = $ilDB->queryF(
214 "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 = %s OR svy_category.owner_fi = %s) ORDER BY svy_phrase_cat.sequence",
215 array('integer', 'integer', 'integer'),
216 array($phrase_id, 0, $ilUser->getId())
217 );
218 while ($row = $ilDB->fetchAssoc($result)) {
219 $neutral = $row["neutral"];
220 if ((int) $row["defaultvalue"] === 1 && (int) $row["owner_fi"] === 0) {
221 $this->columns->addCategory($this->lng->txt($row["title"]), 0, $neutral);
222 } else {
223 $this->columns->addCategory($row["title"], 0, $neutral);
224 }
225 }
226 }
227
231 public function getQuestionDataArray(int $id): array
232 {
233 $ilDB = $this->db;
234
235 $result = $ilDB->queryF(
236 "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",
237 array('integer'),
238 array($id)
239 );
240 if ($result->numRows() === 1) {
241 return $ilDB->fetchAssoc($result);
242 }
243
244 return array();
245 }
246
247 public function loadFromDb(int $question_id): void
248 {
249 $ilDB = $this->db;
250 $result = $ilDB->queryF(
251 "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",
252 array('integer'),
253 array($question_id)
254 );
255 if ($result->numRows() === 1) {
256 $data = $ilDB->fetchAssoc($result);
257 $this->setId((int) $data["question_id"]);
258 $this->setTitle((string) $data["title"]);
259 $this->label = (string) $data['label'];
260 $this->setDescription((string) $data["description"]);
261 $this->setObjId((int) $data["obj_fi"]);
262 $this->setAuthor((string) $data["author"]);
263 $this->setOwner((int) $data["owner_fi"]);
264 $this->setQuestiontext(ilRTE::_replaceMediaObjectImageSrc((string) $data["questiontext"], 1));
265 $this->setObligatory((bool) $data["obligatory"]);
266 $this->setComplete((bool) $data["complete"]);
267 $this->setOriginalId((int) $data["original_id"]);
268 $this->setSubtype((int) $data["subtype"]);
269 $this->setRowSeparators((bool) $data["row_separators"]);
270 $this->setNeutralColumnSeparator((bool) $data["neutral_column_separator"]);
271 $this->setColumnSeparators((bool) $data["column_separators"]);
272 $this->setColumnPlaceholders((bool) $data["column_placeholders"]);
273 $this->setLegend((bool) $data["legend"]);
274 $this->setSingleLineRowCaption((string) $data["singleline_row_caption"]);
275 $this->setRepeatColumnHeader((bool) $data["repeat_column_header"]);
276 $this->setBipolarAdjective(0, (string) $data["bipolar_adjective1"]);
277 $this->setBipolarAdjective(1, (string) $data["bipolar_adjective2"]);
278 $this->setLayout($data["layout"]);
279 $this->flushColumns();
280
281 $result = $ilDB->queryF(
282 "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",
283 array('integer'),
284 array($question_id)
285 );
286 if ($result->numRows() > 0) {
287 while ($data = $ilDB->fetchAssoc($result)) {
288 $this->columns->addCategory((string) $data["title"], (int) $data["other"], (int) $data["neutral"], null, ($data['scale']) ?: ($data['sequence'] + 1));
289 }
290 }
291
292 $result = $ilDB->queryF(
293 "SELECT * FROM svy_qst_matrixrows WHERE question_fi = %s ORDER BY sequence",
294 array('integer'),
295 array($question_id)
296 );
297 while ($row = $ilDB->fetchAssoc($result)) {
298 $this->addRow((string) $row["title"], (string) $row['other'], (string) ($row['label'] ?? ""));
299 }
300 }
301 parent::loadFromDb($question_id);
302 }
303
304 public function isComplete(): bool
305 {
306 return (
307 $this->getTitle() !== '' &&
308 $this->getAuthor() !== '' &&
309 $this->getQuestiontext() !== '' &&
310 $this->getColumnCount() &&
311 $this->getRowCount()
312 );
313 }
314
315 public function saveToDb(int $original_id = 0): int
316 {
317 $ilDB = $this->db;
318
319 $affectedRows = parent::saveToDb($original_id);
320
321 if ($affectedRows === 1) {
322 $ilDB->manipulateF(
323 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
324 array('integer'),
325 array($this->getId())
326 );
327 $ilDB->manipulateF(
328 "INSERT INTO " . $this->getAdditionalTableName() . " (
329 question_fi, subtype, column_separators, row_separators, neutral_column_separator,column_placeholders,
330 legend, singleline_row_caption, repeat_column_header,
331 bipolar_adjective1, bipolar_adjective2, layout, tstamp)
332 VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
333 array(
334 'integer', 'integer', 'text', 'text', 'text', 'integer', 'text', 'text', 'text',
335 'text', 'text', 'text', 'integer'
336 ),
337 array(
338 $this->getId(),
339 $this->getSubtype(),
340 $this->getColumnSeparators(),
341 $this->getRowSeparators(),
342 $this->getNeutralColumnSeparator(),
343 $this->getColumnPlaceholders(),
344 $this->getLegend(),
345 $this->getSingleLineRowCaption(),
346 $this->getRepeatColumnHeader(),
347 $this->getBipolarAdjective(0),
348 $this->getBipolarAdjective(1),
349 serialize($this->getLayout()),
350 time()
351 )
352 );
353
354 // saving material uris in the database
355 $this->saveMaterial();
356
357 $this->saveColumnsToDb();
358 $this->saveRowsToDb();
359 }
360 return $affectedRows;
361 }
362
363 public function saveBipolarAdjectives(
364 string $adjective1,
365 string $adjective2
366 ): void {
367 $ilDB = $this->db;
368
369 $ilDB->manipulateF(
370 "UPDATE " . $this->getAdditionalTableName() . " SET bipolar_adjective1 = %s, bipolar_adjective2 = %s WHERE question_fi = %s",
371 array('text', 'text', 'integer'),
372 array(($adjective1 !== '') ? $adjective1 : null, ($adjective2 !== '') ? $adjective2 : null, $this->getId())
373 );
374 }
375
376 public function saveColumnToDb(
377 string $columntext,
378 int $neutral = 0
379 ): int {
380 $ilUser = $this->user;
381 $ilDB = $this->db;
382
383 $result = $ilDB->queryF(
384 "SELECT title, category_id FROM svy_category WHERE title = %s AND neutral = %s AND owner_fi = %s",
385 array('text', 'text', 'integer'),
386 array($columntext, $neutral, $ilUser->getId())
387 );
388 $insert = false;
389 $returnvalue = "";
390 $insert = true;
391 if ($result->numRows()) {
392 while ($row = $ilDB->fetchAssoc($result)) {
393 if (strcmp($row["title"] ?? '', $columntext) === 0) {
394 $returnvalue = $row["category_id"];
395 $insert = false;
396 }
397 }
398 }
399 if ($insert) {
400 $next_id = $ilDB->nextId('svy_category');
401 $affectedRows = $ilDB->manipulateF(
402 "INSERT INTO svy_category (category_id, title, defaultvalue, owner_fi, neutral, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
403 array('integer', 'text', 'text', 'integer', 'text', 'integer'),
404 array($next_id, $columntext, 0, $ilUser->getId(), $neutral, time())
405 );
406 $returnvalue = $next_id;
407 }
408 return $returnvalue;
409 }
410
411 public function saveColumnsToDb(
412 int $original_id = 0
413 ): void {
414 $ilDB = $this->db;
415
416 // save columns
417 $question_id = $this->getId();
418 if ($original_id > 0) {
419 $question_id = $original_id;
420 }
421
422 // delete existing column relations
423 $affectedRows = $ilDB->manipulateF(
424 "DELETE FROM svy_variable WHERE question_fi = %s",
425 array('integer'),
426 array($question_id)
427 );
428 // create new column relations
429 for ($i = 0; $i < $this->getColumnCount(); $i++) {
430 $cat = $this->getColumn($i);
431 $column_id = $this->saveColumnToDb($cat->title, $cat->neutral);
432 $next_id = $ilDB->nextId('svy_variable');
433 $affectedRows = $ilDB->manipulateF(
434 "INSERT INTO svy_variable (variable_id, category_fi, question_fi, value1, other, sequence, scale, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
435 array('integer','integer','integer','float','integer','integer', 'integer','integer'),
436 array($next_id, $column_id, $question_id, ($i + 1), $cat->other, $i, ($cat->scale > 0) ? $cat->scale : null, time())
437 );
438 }
439 $this->saveCompletionStatus($original_id);
440 }
441
442 public function saveRowsToDb(
443 int $original_id = 0
444 ): void {
445 $ilDB = $this->db;
446
447 // save rows
448 $question_id = $this->getId();
449 if ($original_id > 0) {
450 $question_id = $original_id;
451 }
452
453 // delete existing rows
454 $affectedRows = $ilDB->manipulateF(
455 "DELETE FROM svy_qst_matrixrows WHERE question_fi = %s",
456 array('integer'),
457 array($question_id)
458 );
459 // create new rows
460 for ($i = 0; $i < $this->getRowCount(); $i++) {
461 $row = $this->getRow($i);
462 $next_id = $ilDB->nextId('svy_qst_matrixrows');
463 $affectedRows = $ilDB->manipulateF(
464 "INSERT INTO svy_qst_matrixrows (id_svy_qst_matrixrows, title, label, other, sequence, question_fi) VALUES (%s, %s, %s, %s, %s, %s)",
465 array('integer','text','text','integer','integer','integer'),
466 array($next_id, $row->title, $row->label, ($row->other) ? 1 : 0, $i, $question_id)
467 );
468 }
469 $this->saveCompletionStatus($original_id);
470 }
471
478 public function toXML(
479 bool $a_include_header = true,
480 bool $obligatory_state = false
481 ): string {
482 $a_xml_writer = new ilXmlWriter();
483 $a_xml_writer->xmlHeader();
484 $this->insertXML($a_xml_writer, $a_include_header);
485 $xml = $a_xml_writer->xmlDumpMem(false);
486 if (!$a_include_header) {
487 $pos = strpos($xml, "?>");
488 $xml = substr($xml, $pos + 2);
489 }
490 return $xml;
491 }
492
496 public function insertXML(
497 ilXmlWriter $a_xml_writer,
498 bool $a_include_header = true
499 ): void {
500 $attrs = array(
501 "id" => $this->getId(),
502 "title" => $this->getTitle(),
503 "type" => $this->getQuestionType(),
504 "subtype" => $this->getSubtype(),
505 "obligatory" => $this->getObligatory()
506 );
507 $a_xml_writer->xmlStartTag("question", $attrs);
508
509 $a_xml_writer->xmlElement("description", null, $this->getDescription());
510 $a_xml_writer->xmlElement("author", null, $this->getAuthor());
511 $a_xml_writer->xmlStartTag("questiontext");
512 $this->addMaterialTag($a_xml_writer, $this->getQuestiontext());
513 $a_xml_writer->xmlEndTag("questiontext");
514
515 $a_xml_writer->xmlStartTag("matrix");
516 $a_xml_writer->xmlStartTag("matrixrows");
517 for ($i = 0; $i < $this->getRowCount(); $i++) {
518 $attrs = array(
519 "id" => $i
520 );
521 if (strlen($this->getRow($i)->label)) {
522 $attrs['label'] = $this->getRow($i)->label;
523 }
524 if ($this->getRow($i)->other) {
525 $attrs['other'] = 1;
526 }
527 $a_xml_writer->xmlStartTag("matrixrow", $attrs);
528 $this->addMaterialTag($a_xml_writer, $this->getRow($i)->title);
529 $a_xml_writer->xmlEndTag("matrixrow");
530 }
531 $a_xml_writer->xmlEndTag("matrixrows");
532
533 $a_xml_writer->xmlStartTag("responses");
534 if ($this->getBipolarAdjective(0) !== '' && ($this->getBipolarAdjective(1) !== '')) {
535 $a_xml_writer->xmlStartTag("bipolar_adjectives");
536 $attribs = array(
537 "label" => "0"
538 );
539 $a_xml_writer->xmlElement("adjective", $attribs, $this->getBipolarAdjective(0));
540 $attribs = array(
541 "label" => "1"
542 );
543 $a_xml_writer->xmlElement("adjective", $attribs, $this->getBipolarAdjective(1));
544 $a_xml_writer->xmlEndTag("bipolar_adjectives");
545 }
546 for ($i = 0; $i < $this->getColumnCount(); $i++) {
547 $attrs = array(
548 "id" => $i
549 );
550 if ($this->getColumn($i)->neutral) {
551 $attrs['label'] = 'neutral';
552 }
553 switch ($this->getSubtype()) {
554 case 0:
555 $a_xml_writer->xmlStartTag("response_single", $attrs);
556 break;
557 case 1:
558 $a_xml_writer->xmlStartTag("response_multiple", $attrs);
559 break;
560 }
561 $this->addMaterialTag($a_xml_writer, $this->getColumn($i)->title);
562 switch ($this->getSubtype()) {
563 case 0:
564 $a_xml_writer->xmlEndTag("response_single");
565 break;
566 case 1:
567 $a_xml_writer->xmlEndTag("response_multiple");
568 break;
569 }
570 }
571
572 $a_xml_writer->xmlEndTag("responses");
573 $a_xml_writer->xmlEndTag("matrix");
574
575 if (count($this->material)) {
576 if (preg_match("/il_(\d*?)_(\w+)_(\d+)/", $this->material["internal_link"], $matches)) {
577 $attrs = array(
578 "label" => $this->material["title"]
579 );
580 $a_xml_writer->xmlStartTag("material", $attrs);
581 $intlink = "il_" . IL_INST_ID . "_" . $matches[2] . "_" . $matches[3];
582 if (strcmp($matches[1], "") !== 0) {
583 $intlink = $this->material["internal_link"];
584 }
585 $a_xml_writer->xmlElement("mattext", null, $intlink);
586 $a_xml_writer->xmlEndTag("material");
587 }
588 }
589
590 $a_xml_writer->xmlStartTag("metadata");
591 $a_xml_writer->xmlStartTag("metadatafield");
592 $a_xml_writer->xmlElement("fieldlabel", null, "column_separators");
593 $a_xml_writer->xmlElement("fieldentry", null, $this->getColumnSeparators());
594 $a_xml_writer->xmlEndTag("metadatafield");
595
596 $a_xml_writer->xmlStartTag("metadatafield");
597 $a_xml_writer->xmlElement("fieldlabel", null, "row_separators");
598 $a_xml_writer->xmlElement("fieldentry", null, $this->getRowSeparators());
599 $a_xml_writer->xmlEndTag("metadatafield");
600
601 $a_xml_writer->xmlStartTag("metadatafield");
602 $a_xml_writer->xmlElement("fieldlabel", null, "neutral_column_separator");
603 $a_xml_writer->xmlElement("fieldentry", null, $this->getNeutralColumnSeparator());
604 $a_xml_writer->xmlEndTag("metadatafield");
605
606 $a_xml_writer->xmlStartTag("metadatafield");
607 $a_xml_writer->xmlElement("fieldlabel", null, "layout");
608 $a_xml_writer->xmlElement("fieldentry", null, serialize($this->getLayout()));
609 $a_xml_writer->xmlEndTag("metadatafield");
610
611 $a_xml_writer->xmlEndTag("metadata");
612
613 $a_xml_writer->xmlEndTag("question");
614 }
615
616 public function syncWithOriginal(): void
617 {
618 if ($this->getOriginalId()) {
619 parent::syncWithOriginal();
620 $this->saveColumnsToDb($this->getOriginalId());
621 $this->saveRowsToDb($this->getOriginalId());
622 }
623 }
624
628 public function addStandardNumbers(
629 int $lower_limit,
630 int $upper_limit
631 ): void {
632 for ($i = $lower_limit; $i <= $upper_limit; $i++) {
633 $this->columns->addCategory($i);
634 }
635 }
636
641 public function savePhrase(
642 string $title
643 ): void {
644 $ilUser = $this->user;
645 $ilDB = $this->db;
646
647 $next_id = $ilDB->nextId('svy_phrase');
648 $ilDB->manipulateF(
649 "INSERT INTO svy_phrase (phrase_id, title, defaultvalue, owner_fi, tstamp) VALUES (%s, %s, %s, %s, %s)",
650 array('integer','text','text','integer','integer'),
651 array($next_id, $title, 1, $ilUser->getId(), time())
652 );
653 $phrase_id = $next_id;
654
655 $counter = 1;
656 $phrase_data = $this->edit_manager->getPhraseData();
657 foreach ($phrase_data as $data) {
658 $next_id = $ilDB->nextId('svy_category');
659 $affectedRows = $ilDB->manipulateF(
660 "INSERT INTO svy_category (category_id, title, defaultvalue, owner_fi, tstamp, neutral) VALUES (%s, %s, %s, %s, %s, %s)",
661 array('integer','text','text','integer','integer','text'),
662 array($next_id, $data['answer'], 1, $ilUser->getId(), time(), $data['neutral'])
663 );
664 $category_id = $next_id;
665 $next_id = $ilDB->nextId('svy_phrase_cat');
666 $affectedRows = $ilDB->manipulateF(
667 "INSERT INTO svy_phrase_cat (phrase_category_id, phrase_fi, category_fi, sequence, other, scale) VALUES (%s, %s, %s, %s, %s, %s)",
668 array('integer', 'integer', 'integer','integer', 'integer', 'integer'),
669 array($next_id, $phrase_id, $category_id, $counter, ($data['other']) ? 1 : 0, $data['scale'])
670 );
671 $counter++;
672 }
673 }
674
675 public function getQuestionType(): string
676 {
677 return "SurveyMatrixQuestion";
678 }
679
683 public function getAdditionalTableName(): string
684 {
685 return "svy_qst_matrix";
686 }
687
688 public function getWorkingDataFromUserInput(array $post_data): array
689 {
690 $data = array();
691 foreach ($post_data as $key => $value) {
692 switch ($this->getSubtype()) {
693 case 1:
694 case 0:
695 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
696 if (is_array($value)) {
697 foreach ($value as $val) {
698 $data[] = array("value" => $val,
699 "rowvalue" => $matches[1],
700 "textanswer" => $post_data['matrix_other_' . $this->getId(
701 ) . '_' . $matches[1]] ?? ""
702 );
703 }
704 } else {
705 $data[] = array("value" => $value,
706 "rowvalue" => $matches[1],
707 "textanswer" => $post_data['matrix_other_' . $this->getId(
708 ) . '_' . $matches[1]] ?? ""
709 );
710 }
711 }
712 break;
713 }
714 }
715 return $data;
716 }
717
723 public function checkUserInput(
724 array $post_data,
725 int $survey_id
726 ): string {
727 if (!$this->getObligatory()) {
728 return "";
729 }
730 switch ($this->getSubtype()) {
731 case 0:
732 $counter = 0;
733 foreach ($post_data as $key => $value) {
734 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
735 if (array_key_exists('matrix_other_' . $this->getId() . "_" . $matches[1], $post_data) && strlen($post_data['matrix_other_' . $this->getId() . "_" . $matches[1]]) == 0) {
736 return $this->lng->txt("question_mr_no_other_answer");
737 }
738 $counter++;
739 }
740 }
741 if ($counter !== $this->getRowCount()) {
742 return $this->lng->txt("matrix_question_radio_button_not_checked");
743 }
744 break;
745 case 1:
746 $counter = 0;
747 foreach ($post_data as $key => $value) {
748 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
749 if (array_key_exists('matrix_other_' . $this->getId() . "_" . $matches[1], $post_data) && strlen($post_data['matrix_other_' . $this->getId() . "_" . $matches[1]]) == 0) {
750 return $this->lng->txt("question_mr_no_other_answer");
751 }
752 $counter++;
753 if ((!is_array($value)) || (count($value) < 1)) {
754 return $this->lng->txt("matrix_question_checkbox_not_checked");
755 }
756 }
757 }
758 if ($counter !== $this->getRowCount()) {
759 return $this->lng->txt("matrix_question_checkbox_not_checked");
760 }
761 break;
762 }
763 return "";
764 }
765
766 public function saveUserInput(
767 array $post_data,
768 int $active_id,
769 bool $a_return = false
770 ): ?array {
771 $ilDB = $this->db;
772
773 $answer_data = array();
774
775 // gather data
776 switch ($this->getSubtype()) {
777 case 0:
778 foreach ($post_data as $key => $value) {
779 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
780 if (strlen($value)) {
781 $other_value = (array_key_exists('matrix_other_' . $this->getId() . '_' . $matches[1], $post_data))
782 ? $this->stripSlashesAddSpaceFallback($post_data['matrix_other_' . $this->getId() . '_' . $matches[1]])
783 : null;
784 $answer_data[] = array("value" => $value,
785 "textanswer" => $other_value,
786 "rowvalue" => $matches[1]);
787 }
788 }
789 }
790 break;
791
792 case 1:
793 foreach ($post_data as $key => $value) {
794 if (preg_match("/matrix_" . $this->getId() . "_(\d+)/", $key, $matches)) {
795 $other_value = (array_key_exists('matrix_other_' . $this->getId() . '_' . $matches[1], $post_data))
796 ? $this->stripSlashesAddSpaceFallback($post_data['matrix_other_' . $this->getId() . '_' . $matches[1]])
797 : null;
798 foreach ($value as $checked) {
799 $answer_data[] = array("value" => $checked,
800 "textanswer" => $other_value,
801 "rowvalue" => $matches[1]);
802 }
803 }
804 }
805 break;
806 }
807
808 if ($a_return) {
809 return $answer_data;
810 }
811
812 // #16387 - only if any input
813 if (count($answer_data)) {
814 // save data
815 foreach ($answer_data as $item) {
816 $next_id = $ilDB->nextId('svy_answer');
817 #20216
818 $fields = array();
819 $fields['answer_id'] = array("integer", $next_id);
820 $fields['question_fi'] = array("integer", $this->getId());
821 $fields['active_fi'] = array("integer", $active_id);
822 $fields['value'] = array("float", $item['value']);
823 $fields['textanswer'] = array("clob", $item['textanswer']);
824 $fields['rowvalue'] = array("integer", $item['rowvalue']);
825 $fields['tstamp'] = array("integer", time());
826
827 $affectedRows = $ilDB->insert("svy_answer", $fields);
828 }
829 }
830 return null;
831 }
832
837 int $question_id
838 ): void {
839 parent::deleteAdditionalTableData($question_id);
840
841 $ilDB = $this->db;
842 $ilDB->manipulateF(
843 "DELETE FROM svy_qst_matrixrows WHERE question_fi = %s",
844 array('integer'),
845 array($question_id)
846 );
847 }
848
852 public function getSubtype(): ?int
853 {
854 return $this->subtype;
855 }
856
860 public function setSubtype(int $a_subtype = 0): void
861 {
862 switch ($a_subtype) {
863 case 1:
864 case 2:
865 case 3:
866 case 4:
867 case 5:
868 case 6:
869 $this->subtype = $a_subtype;
870 break;
871 case 0:
872 default:
873 $this->subtype = 0;
874 break;
875 }
876 }
877
881 public function setColumnSeparators(bool $enable = false): void
882 {
883 $this->columnSeparators = $enable;
884 }
885
886 public function getColumnSeparators(): bool
887 {
888 return $this->columnSeparators;
889 }
890
894 public function setRowSeparators(bool $enable = false): void
895 {
896 $this->rowSeparators = $enable;
897 }
898
899 public function getRowSeparators(): bool
900 {
901 return $this->rowSeparators;
902 }
903
904 public function setNeutralColumnSeparator(bool $enable = true): void
905 {
906 $this->neutralColumnSeparator = $enable;
907 }
908
909 public function getNeutralColumnSeparator(): bool
910 {
911 return $this->neutralColumnSeparator;
912 }
913
917 public function importAdditionalMetadata(array $a_meta): void
918 {
919 foreach ($a_meta as $key => $value) {
920 switch ($value["label"]) {
921 case "column_separators":
922 $this->setColumnSeparators($value["entry"]);
923 break;
924 case "row_separators":
925 $this->setRowSeparators($value["entry"]);
926 break;
927 case "layout":
928 $this->setLayout($value["entry"]);
929 break;
930 case "neutral_column_separator":
931 $this->setNeutralColumnSeparator($value["entry"]);
932 break;
933 }
934 }
935 }
936
940 public function importAdjectives(array $a_data): void
941 {
942 $i = 0;
943 foreach ($a_data as $adjective) {
944 if (is_numeric($adjective["label"])) {
945 $this->setBipolarAdjective($adjective["label"], $adjective["text"]);
946 } else {
947 $this->setBipolarAdjective($i, $adjective["text"]);
948 }
949 $i++;
950 }
951 }
952
956 public function importMatrix(
957 array $a_data
958 ): void {
959 foreach ($a_data as $row) {
960 $this->addRow($row['title'], $row['other'], $row['label']);
961 }
962 }
963
967 public function importResponses(array $a_data): void
968 {
969 foreach ($a_data as $id => $data) {
970 $column = "";
971 foreach ($data["material"] as $material) {
972 $column .= $material["text"];
973 }
974 $this->columns->addCategory($column, 0, strcmp($data["label"], "neutral") == 0);
975 }
976 }
977
981 public function usableForPrecondition(): bool
982 {
983 return false;
984 }
985
989 public function getPreconditionValueOutput(string $value): string
990 {
991 return $value;
992 }
993
998 string $default,
999 string $title,
1000 string $variable
1001 ): ?ilFormPropertyGUI {
1002 $step3 = new ilSelectInputGUI($title, $variable);
1003 $options = $this->getPreconditionOptions();
1004 $step3->setOptions($options);
1005 $step3->setValue($default);
1006 return $step3;
1007 }
1008
1018 public function saveLayout(
1019 float $percent_row,
1020 float $percent_columns,
1021 float $percent_bipolar_adjective1 = 0,
1022 float $percent_bipolar_adjective2 = 0,
1023 float $percent_neutral = 0
1024 ): void {
1025 $ilDB = $this->db;
1026
1027 $layout = array(
1028 "percent_row" => $percent_row,
1029 "percent_columns" => $percent_columns,
1030 "percent_bipolar_adjective1" => $percent_bipolar_adjective1,
1031 "percent_bipolar_adjective2" => $percent_bipolar_adjective2,
1032 "percent_neutral" => $percent_neutral
1033 );
1034 $affectedRows = $ilDB->manipulateF(
1035 "UPDATE " . $this->getAdditionalTableName() . " SET layout = %s WHERE question_fi = %s",
1036 array('text', 'integer'),
1037 array(serialize($layout), $this->getId())
1038 );
1039 }
1040
1041 public function getLayout(): array
1042 {
1043 if (count($this->layout) === 0) {
1044 if ($this->hasBipolarAdjectives() && $this->hasNeutralColumn()) {
1045 $this->layout = array(
1046 "percent_row" => 30,
1047 "percent_columns" => 40,
1048 "percent_bipolar_adjective1" => 10,
1049 "percent_bipolar_adjective2" => 10,
1050 "percent_neutral" => 10
1051 );
1052 } elseif ($this->hasBipolarAdjectives()) {
1053 $this->layout = array(
1054 "percent_row" => 30,
1055 "percent_columns" => 50,
1056 "percent_bipolar_adjective1" => 10,
1057 "percent_bipolar_adjective2" => 10,
1058 "percent_neutral" => 0
1059 );
1060 } elseif ($this->hasNeutralColumn()) {
1061 $this->layout = array(
1062 "percent_row" => 30,
1063 "percent_columns" => 50,
1064 "percent_bipolar_adjective1" => 0,
1065 "percent_bipolar_adjective2" => 0,
1066 "percent_neutral" => 20
1067 );
1068 } else {
1069 $this->layout = array(
1070 "percent_row" => 30,
1071 "percent_columns" => 70,
1072 "percent_bipolar_adjective1" => 0,
1073 "percent_bipolar_adjective2" => 0,
1074 "percent_neutral" => 0
1075 );
1076 }
1077 }
1078 return $this->layout;
1079 }
1080
1084 public function setLayout($layout): void
1085 {
1086 if (is_array($layout)) {
1087 $this->layout = $layout;
1088 } else {
1089 $this->layout = unserialize($layout, ['allowed_classes' => false]) ?: [];
1090 }
1091 }
1092
1096 public function hasBipolarAdjectives(): bool
1097 {
1098 return $this->getBipolarAdjective(0) !== '' && $this->getBipolarAdjective(1) !== '';
1099 }
1100
1104 public function hasNeutralColumn(): bool
1105 {
1106 for ($i = 0; $i < $this->getColumnCount(); $i++) {
1107 $column = $this->getColumn($i);
1108 if ($column->neutral && strlen($column->title)) {
1109 return true;
1110 }
1111 }
1112 return false;
1113 }
1114
1118 public function setColumnPlaceholders(bool $a_value = false): void
1119 {
1120 $this->columnPlaceholders = $a_value;
1121 }
1122
1123 public function getColumnPlaceholders(): bool
1124 {
1125 return $this->columnPlaceholders;
1126 }
1127
1131 public function setLegend(bool $a_value = false): void
1132 {
1133 $this->legend = $a_value;
1134 }
1135
1136 public function getLegend(): bool
1137 {
1138 return $this->legend;
1139 }
1140
1141 public function setSingleLineRowCaption(bool $a_value = false): void
1142 {
1143 $this->singleLineRowCaption = $a_value;
1144 }
1145
1146 public function getSingleLineRowCaption(): bool
1147 {
1148 return $this->singleLineRowCaption;
1149 }
1150
1151 public function setRepeatColumnHeader(bool $a_value = false): void
1152 {
1153 $this->repeatColumnHeader = $a_value;
1154 }
1155
1156 public function getRepeatColumnHeader(): bool
1157 {
1158 return $this->repeatColumnHeader;
1159 }
1160
1161
1162 public function getRows(): SurveyCategories
1163 {
1164 return $this->rows;
1165 }
1166
1167 public static function getMaxSumScore(int $survey_id): int
1168 {
1169 global $DIC;
1170
1171 // we need max scale values of matrix rows * number of rows (type 5)
1172 $db = $DIC->database();
1173
1174 $set = $db->queryF(
1175 "SELECT MAX(scale) max_sum_score, q.question_id FROM svy_svy_qst sq " .
1176 "JOIN svy_question q ON (sq.question_fi = q.question_id) " .
1177 "JOIN svy_variable v ON (v.question_fi = q.question_id) " .
1178 "WHERE sq.survey_fi = %s AND q.questiontype_fi = %s " .
1179 "GROUP BY (q.question_id)",
1180 ["integer", "integer"],
1181 [$survey_id, 5]
1182 );
1183 $max_score = [];
1184 while ($rec = $db->fetchAssoc($set)) {
1185 $max_score[$rec["question_id"]] = $rec["max_sum_score"];
1186 }
1187
1188 $set = $db->queryF(
1189 "SELECT COUNT(mr.id_svy_qst_matrixrows) cnt_rows, q.question_id FROM svy_svy_qst sq " .
1190 "JOIN svy_question q ON (sq.question_fi = q.question_id) " .
1191 "JOIN svy_qst_matrixrows mr ON (mr.question_fi = q.question_id) " .
1192 "WHERE sq.survey_fi = %s AND q.questiontype_fi = %s " .
1193 "GROUP BY (q.question_id)",
1194 ["integer", "integer"],
1195 [$survey_id, 5]
1196 );
1197 $cnt_rows = [];
1198 while ($rec = $db->fetchAssoc($set)) {
1199 $cnt_rows[$rec["question_id"]] = $rec["cnt_rows"];
1200 }
1201
1202 $sum_sum_score = 0;
1203 foreach ($max_score as $qid => $s) {
1204 $sum_sum_score += $s * $cnt_rows[$qid];
1205 }
1206
1207 return $sum_sum_score;
1208 }
1209}
$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...
savePhrase(string $title)
Saves a set of columns to a default phrase (data currently comes from session)
__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.
addPhrase(int $phrase_id)
Adds a phrase to the question.
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.
if(!file_exists(getcwd() . '/ilias.ini.php'))
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: confirmReg.php:20
const IL_INST_ID
Definition: constants.php:40
global $DIC
Definition: feed.php:28
$ilUser
Definition: imgupload.php:34
if($format !==null) $name
Definition: metadata.php:247
$index
Definition: metadata.php:145
$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
$rows
Definition: xhr_table.php:10