ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.SurveyQuestionEvaluation.php
Go to the documentation of this file.
1<?php
2
25{
26 protected ilLanguage $lng;
27 protected ilDBInterface $db;
29 protected array $finished_ids;
30 protected int $chart_width = 400;
31 protected int $chart_height = 300;
32
33 public function __construct(
34 SurveyQuestion $a_question,
35 array $a_finished_ids = []
36 ) {
37 global $DIC;
38
39 $this->lng = $DIC->language();
40 $this->db = $DIC->database();
41 $this->question = $a_question;
42 $this->finished_ids = $a_finished_ids;
43 }
44
45
46 //
47 // RESULTS
48 //
49
55 public function getResults()
56 {
57 $results = new ilSurveyEvaluationResults($this->question);
58 $answers = $this->getAnswerData();
59
60 $this->parseResults(
62 (array) ($answers[0] ?? []),
63 method_exists($this->question, "getCategories")
64 ? $this->question->getCategories()
65 : null
66 );
67
68 return $results;
69 }
70
75 public function getSumScores(): array
76 {
78
79 $res = [];
80
81 $sql = "SELECT svy_answer.* FROM svy_answer" .
82 " JOIN svy_finished ON (svy_finished.finished_id = svy_answer.active_fi)" .
83 " WHERE svy_answer.question_fi = " . $ilDB->quote($this->question->getId(), "integer") .
84 " AND svy_finished.survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer");
85 if (count($this->finished_ids) > 0) {
86 $sql .= " AND " . $ilDB->in("svy_finished.finished_id", $this->finished_ids, "", "integer");
87 }
88 $set = $ilDB->query($sql);
89 $cnt_answer_records = [];
90 while ($row = $ilDB->fetchAssoc($set)) {
91 $key = (int) $row["active_fi"];
92 $cnt_answer_records[$key] = ($cnt_answer_records[$key] ?? 0) + 1;
93 if ($this->supportsSumScore()) {
94 $res[$key] = ($res[$key] ?? 0) + $row["value"] + 1;
95 } else {
96 $res[$key] = 0;
97 }
98 }
99
100 foreach ($res as $active_id => $sum_score) {
101 if (!$this->isSumScoreValid($cnt_answer_records[$active_id])) {
102 $res[$active_id] = null;
103 }
104 }
105 return $res;
106 }
107
111 protected function isSumScoreValid(int $nr_answer_records): bool
112 {
113 return true;
114 }
115
116 protected function supportsSumScore(): bool
117 {
118 return false;
119 }
120
124 protected function parseResults(
125 ilSurveyEvaluationResults $a_results,
126 array $a_answers,
127 ?SurveyCategories $a_categories = null
128 ): void {
129 $num_users_answered = count($a_answers);
130
131 $a_results->setUsersAnswered($num_users_answered);
132 $a_results->setUsersSkipped($this->getNrOfParticipants() - $num_users_answered);
133
134 // parse answers
135 $has_multi = false;
136 $selections = array();
137 foreach ($a_answers as $active_id => $answers) {
138 // :TODO:
139 if (count($answers) > 1) {
140 $has_multi = true;
141 }
142 foreach ($answers as $answer) {
143 // map selection value to scale/category
144 if ($a_categories &&
145 $answer["value"] != "") {
146 $scale = $a_categories->getCategoryForScale($answer["value"] + 1);
147 if ($scale instanceof ilSurveyCategory) {
148 $answer["value"] = $scale->scale;
149 }
150 }
152 $active_id,
153 (float) $answer["value"],
154 (string) $answer["text"],
155 $answer["tstamp"]
156 );
157 $a_results->addAnswer($parsed);
158
159 if ($answer["value"] != "") {
160 if (!isset($selections[(string) $answer["value"]])) {
161 $selections[(string) $answer["value"]] = 0;
162 }
163 $selections[(string) $answer["value"]]++;
164 }
165 }
166 }
167
168 $total = array_sum($selections);
169
170 if ($total) {
171 // mode
172 $mode_nr = max($selections);
173 $tmp_mode = $selections;
174 asort($tmp_mode, SORT_NUMERIC);
175 $mode = array_keys($tmp_mode, $mode_nr);
176 $a_results->setMode($mode, $mode_nr);
177
178 if (!$has_multi) {
179 // median
180 ksort($selections, SORT_NUMERIC);
181 $median = array();
182 foreach ($selections as $value => $count) {
183 for ($i = 0; $i < $count; $i++) {
184 $median[] = $value;
185 }
186 }
187 if ($total % 2 === 0) {
188 $lower = $median[($total / 2) - 1];
189 $upper = $median[($total / 2)];
190 $median_value = 0.5 * ($lower + $upper);
191 if ($a_categories &&
192 round($median_value) != $median_value) {
193 // mapping calculated value to scale values
194 $median_value = array($lower, $upper);
195 }
196 } else {
197 $median_value = $median[(($total + 1) / 2) - 1];
198 }
199 $a_results->setMedian($median_value);
200 }
201 }
202
203 if ($a_categories) {
204 // selections by category
205 for ($c = 0; $c < $a_categories->getCategoryCount(); $c++) {
206 $cat = $a_categories->getCategory($c);
207 $scale = $cat->scale;
208
209 $perc = null;
210 if ($total && isset($selections[$scale])) {
211 $perc = $selections[$scale] / $total;
212 }
214 $cat,
215 $selections[$scale] ?? null,
216 $perc
217 );
218 $a_results->addVariable($var);
219 }
220 }
221 }
222
226 public function parseUserSpecificResults($a_qres, int $a_user_id): array
227 {
228 $parsed_results = array();
229 $tmp = "";
230 if (is_array($a_qres)) {
231 foreach ($a_qres as $row_idx => $row_results) {
232 $row_title = $row_results[0];
233 $user_results = $row_results[1]->getUserResults($a_user_id);
234 if ($user_results) {
235 foreach ($user_results as $item) {
236 // :TODO: layout
237 $tmp = $row_title . ": ";
238 if ($item[0] !== "") {
239 $tmp .= $item[0];
240 }
241 if ($item[1] && $item[0]) {
242 $tmp .= ", \"" . nl2br($item[1]) . "\"";
243 } elseif ($item[1]) {
244 $tmp .= "\"" . nl2br($item[1]) . "\"";
245 }
246 $parsed_results[$row_idx . "-" . $item[2]] = $tmp;
247 }
248 }
249 }
250 } else {
251 $user_results = $a_qres->getUserResults($a_user_id);
252 if ($user_results) {
253 foreach ($user_results as $item) {
254 // :TODO: layout
255 if ($item[0] !== "") {
256 $tmp = $item[0];
257 }
258 if ($item[1] && $item[0]) {
259 $tmp .= ", \"" . nl2br($item[1]) . "\"";
260 } elseif ($item[1]) {
261 $tmp = "\"" . nl2br($item[1]) . "\"";
262 }
263 $parsed_results[(int) $item[2]] = $tmp;
264 }
265 }
266 }
267
268 return $parsed_results;
269 }
270
271
272 //
273 // DETAILS
274 //
275
280 public function getGrid(
281 $a_results,
282 bool $a_abs = true,
283 bool $a_perc = true
284 ): array {
285 $lng = $this->lng;
286
287 if ($a_abs && $a_perc) {
288 $cols = array(
289 $lng->txt("category_nr_selected"),
290 $lng->txt("svy_fraction_of_selections")
291 );
292 } elseif ($a_abs) {
293 $cols = array(
294 $lng->txt("category_nr_selected")
295 );
296 } else {
297 $cols = array(
298 $lng->txt("svy_fraction_of_selections")
299 );
300 }
301
302 $res = array(
303 "cols" => $cols,
304 "rows" => array()
305 );
306
307 $vars = $a_results->getVariables();
308 if ($vars) {
309 foreach ($vars as $var) {
310 $perc = $var->perc
311 ? sprintf("%.2f", $var->perc * 100) . "%"
312 : "0%";
313
314 if ($a_abs && $a_perc) {
315 $res["rows"][] = array(
316 $var->cat->title,
317 $var->abs,
318 $perc
319 );
320 } elseif ($a_abs) {
321 $res["rows"][] = array(
322 $var->cat->title,
323 $var->abs
324 );
325 } else {
326 $res["rows"][] = array(
327 $var->cat->title,
328 $perc
329 );
330 }
331 }
332 }
333
334 return $res;
335 }
336
342 public function getTextAnswers($a_results): array
343 {
344 return $a_results->getMappedTextAnswers();
345 }
346
347 protected function getChartColors(): array
348 {
349 return array(
350 // flot "default" theme
351 "#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed",
352 // http://godsnotwheregodsnot.blogspot.de/2012/09/color-distribution-methodology.html
353 "#1CE6FF", "#FF34FF", "#FF4A46", "#008941", "#006FA6", "#A30059",
354 "#FFDBE5", "#7A4900", "#0000A6", "#63FFAC", "#B79762", "#004D43", "#8FB0FF", "#997D87",
355 "#5A0007", "#809693", "#FEFFE6", "#1B4400", "#4FC601", "#3B5DFF", "#4A3B53", "#FF2F80",
356 "#61615A", "#BA0900", "#6B7900", "#00C2A0", "#FFAA92", "#FF90C9", "#B903AA", "#D16100",
357 "#DDEFFF", "#000035", "#7B4F4B", "#A1C299", "#300018", "#0AA6D8", "#013349", "#00846F",
358 "#372101", "#FFB500", "#C2FFED", "#A079BF", "#CC0744", "#C0B9B2", "#C2FF99", "#001E09",
359 "#00489C", "#6F0062", "#0CBD66", "#EEC3FF", "#456D75", "#B77B68", "#7A87A1", "#788D66",
360 "#885578", "#FAD09F", "#FF8A9A", "#D157A0", "#BEC459", "#456648", "#0086ED", "#886F4C",
361 "#34362D", "#B4A8BD", "#00A6AA", "#452C2C", "#636375", "#A3C8C9", "#FF913F", "#938A81",
362 "#575329", "#00FECF", "#B05B6F", "#8CD0FF", "#3B9700", "#04F757", "#C8A1A1", "#1E6E00",
363 "#7900D7", "#A77500", "#6367A9", "#A05837", "#6B002C", "#772600", "#D790FF", "#9B9700",
364 "#549E79", "#FFF69F", "#201625", "#72418F", "#BC23FF", "#99ADC0", "#3A2465", "#922329",
365 "#5B4534", "#FDE8DC", "#404E55", "#0089A3", "#CB7E98", "#A4E804", "#324E72", "#6A3A4C"
366 );
367 }
368
372 public function getChart($a_results): ?array
373 {
374 $chart = ilChart::getInstanceByType(ilChart::TYPE_GRID, $a_results->getQuestion()->getId());
375 $chart->setYAxisToInteger(true);
376
377 $colors = $this->getChartColors();
378 $chart->setColors($colors);
379
380 // :TODO:
381 $chart->setSize((string) $this->chart_width, (string) $this->chart_height);
382
383 $vars = $a_results->getVariables();
384
385 $legend = $labels = array();
386 foreach ($vars as $idx => $var) {
387 $data = $chart->getDataInstance(ilChartGrid::DATA_BARS);
388 $data->setBarOptions(0.5, "center");
389 $data->setFill(1);
390 $chart->addData($data);
391
392 // labels
393 $labels[$idx] = "";
394 $legend[] = array(
395 $var->cat->title,
396 $colors[$idx]
397 );
398 $data->setLabel($var->cat->title);
399
400 $data->addPoint($idx, $var->abs);
401 }
402
403 $chart->setTicks($labels, false, true);
404
405 return array(
406 $chart->getHTML(),
407 $legend
408 );
409 }
410
411
412 //
413 // USER-SPECIFIC
414 //
415
419 public function getSkippedValue(): string
420 {
422 }
423
424
425 //
426 // HELPER
427 //
428
429 protected function getSurveyId(): int
430 {
431 $ilDB = $this->db;
432
433 // #18968
434 $set = $ilDB->query("SELECT survey_fi" .
435 " FROM svy_svy_qst" .
436 " WHERE question_fi = " . $ilDB->quote($this->question->getId(), "integer"));
437 $row = $ilDB->fetchAssoc($set);
438 return $row["survey_fi"];
439 }
440
441
445 protected function getNrOfParticipants(): int
446 {
447 $ilDB = $this->db;
448
449 if (count($this->finished_ids) > 0) {
450 return count($this->finished_ids);
451 }
452
453 $set = $ilDB->query("SELECT finished_id FROM svy_finished" .
454 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer"));
455 return $set->numRows();
456 }
457
458 protected function getAnswerData(): array
459 {
460 $ilDB = $this->db;
461
462 $res = array();
463
464 $sql = "SELECT svy_answer.* FROM svy_answer" .
465 " JOIN svy_finished ON (svy_finished.finished_id = svy_answer.active_fi)" .
466 " WHERE svy_answer.question_fi = " . $ilDB->quote($this->question->getId(), "integer") .
467 " AND svy_finished.survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer");
468 if (count($this->finished_ids) > 0) {
469 $sql .= " AND " . $ilDB->in("svy_finished.finished_id", $this->finished_ids, "", "integer");
470 }
471 $set = $ilDB->query($sql);
472 while ($row = $ilDB->fetchAssoc($set)) {
473 $res[(int) $row["rowvalue"]][(int) $row["active_fi"]][] = array(
474 "value" => $row["value"],
475 "text" => $row["textanswer"],
476 "tstamp" => $row["tstamp"]
477 );
478 }
479
480 return $res;
481 }
482
483
484 //
485 // EXPORT
486 //
487
491 public function exportResults(
492 $a_results,
493 bool $a_do_title,
494 bool $a_do_label
495 ): array {
496 $question = $a_results->getQuestion();
497
498 $res = array();
499
500 if ($a_do_title) {
501 $res[] = $question->getTitle();
502 }
503 if ($a_do_label) {
504 $res[] = $question->label;
505 }
506
507 $res[] = $question->getQuestiontext();
509
510 $res[] = (int) $a_results->getUsersAnswered();
511 $res[] = (int) $a_results->getUsersSkipped();
512
513 // :TODO:
514 $res[] = is_array($a_results->getModeValue())
515 ? implode(", ", $a_results->getModeValue())
516 : $a_results->getModeValue();
517
518 $res[] = $a_results->getModeValueAsText();
519 $res[] = (int) $a_results->getModeNrOfSelections();
520
521 // :TODO:
522 $res[] = $a_results->getMedianAsText();
523
524 $res[] = $a_results->getMean();
525
526 return array($res);
527 }
528
533 public function getExportGrid($a_results): array
534 {
536
537 $res = array(
538 "cols" => array(
539 $lng->txt("title"),
540 $lng->txt("value"),
541 $lng->txt("category_nr_selected"),
542 $lng->txt("svy_fraction_of_selections")
543 ),
544 "rows" => array()
545 );
546
547 $vars = $a_results->getVariables();
548 if ($vars) {
549 foreach ($vars as $var) {
550 $res["rows"][] = array(
551 $var->cat->title,
552 $var->cat->scale,
553 $var->abs,
554 $var->perc
555 ? sprintf("%.2f", $var->perc * 100) . "%"
556 : "0%"
557 );
558 }
559 }
560
561 return $res;
562 }
563
572 array &$a_title_row,
573 array &$a_title_row2,
574 bool $a_do_title,
575 bool $a_do_label
576 ): void {
577 // type-specific
578 }
579
585 abstract public function addUserSpecificResults(array &$a_row, int $a_user_id, $a_results): void;
586}
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...
__construct(SurveyQuestion $a_question, array $a_finished_ids=[])
getSkippedValue()
Get caption for skipped value.
exportResults( $a_results, bool $a_do_title, bool $a_do_label)
getGrid( $a_results, bool $a_abs=true, bool $a_perc=true)
Get grid data.
parseResults(ilSurveyEvaluationResults $a_results, array $a_answers, ?SurveyCategories $a_categories=null)
Parse answer data into results instance.
isSumScoreValid(int $nr_answer_records)
Is sum score ok (question needs to be fully answered)
getExportGrid($a_results)
Get grid data.
getUserSpecificVariableTitles(array &$a_title_row, array &$a_title_row2, bool $a_do_title, bool $a_do_label)
Get title columns for user-specific export.
getSumScores()
Get sum score for this question for all active ids of run.
parseUserSpecificResults($a_qres, int $a_user_id)
getTextAnswers($a_results)
Get text answers.
getNrOfParticipants()
Returns the number of participants for a survey.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getQuestionTypeName(string $type_tag)
Return the translation for a given question type.
static getInstanceByType(int $a_type, string $a_id)
const TYPE_GRID
language handling
static getSurveySkippedValue()
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...
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...
addVariable(ilSurveyEvaluationResultsVariable $a_variable)
addAnswer(ilSurveyEvaluationResultsAnswer $a_answer)
setMode( $a_value, int $a_nr_of_selections)
$c
Definition: deliver.php:25
Interface ilDBInterface.
$res
Definition: ltiservices.php:69
global $lng
Definition: privfeed.php:31
$results
global $DIC
Definition: shib_login.php:26