ILIAS  release_7 Revision v7.30-3-g800a261c036
class.SurveyQuestionEvaluation.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
4
11{
15 protected $lng;
16
20 protected $db;
21
22 protected $question; // [SurveyQuestion]
23 protected $finished_ids; // [array]
24 protected $chart_width = 400;
25 protected $chart_height = 300;
26
34 public function __construct(SurveyQuestion $a_question, array $a_finished_ids = null)
35 {
36 global $DIC;
37
38 $this->lng = $DIC->language();
39 $this->db = $DIC->database();
40 $this->question = $a_question;
41 $this->finished_ids = $a_finished_ids;
42 }
43
44
45 //
46 // RESULTS
47 //
48
54 public function getResults()
55 {
56 $results = new ilSurveyEvaluationResults($this->question);
57 $answers = $this->getAnswerData();
58
59 $this->parseResults(
61 (array) $answers[0],
62 method_exists($this->question, "getCategories")
63 ? $this->question->getCategories()
64 : null
65 );
66
67 return $results;
68 }
69
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 (is_array($this->finished_ids)) {
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 $cnt_answer_records[(int) $row["active_fi"]] += 1;
92 if ($this->supportsSumScore()) {
93 $res[(int) $row["active_fi"]] += $row["value"] + 1;
94 } else {
95 $res[(int) $row["active_fi"]] = 0;
96 }
97 }
98
99 foreach ($res as $active_id => $sum_score) {
100 if (!$this->isSumScoreValid($cnt_answer_records[$active_id])) {
101 $res[$active_id] = null;
102 }
103 }
104 return $res;
105 }
106
112 protected function isSumScoreValid(int $nr_answer_records) : bool
113 {
114 return true;
115 }
116
121 protected function supportsSumScore() : bool
122 {
123 return false;
124 }
125
133 protected function parseResults(ilSurveyEvaluationResults $a_results, array $a_answers, SurveyCategories $a_categories = null)
134 {
135 $num_users_answered = sizeof($a_answers);
136
137 $a_results->setUsersAnswered($num_users_answered);
138 $a_results->setUsersSkipped($this->getNrOfParticipants() - $num_users_answered);
139
140 // parse answers
141 $has_multi = false;
142 $selections = array();
143 foreach ($a_answers as $active_id => $answers) {
144 // :TODO:
145 if (sizeof($answers) > 1) {
146 $has_multi = true;
147 }
148 foreach ($answers as $answer) {
149 // map selection value to scale/category
150 if ($a_categories &&
151 $answer["value"] != "") {
152 $scale = $a_categories->getCategoryForScale($answer["value"] + 1);
153 if ($scale instanceof ilSurveyCategory) {
154 $answer["value"] = $scale->scale;
155 }
156 }
157
159 $active_id,
160 $answer["value"],
161 $answer["text"]
162 );
163 $a_results->addAnswer($parsed);
164
165 if ($answer["value"] != "") {
166 $selections[$answer["value"]]++;
167 }
168 }
169 }
170
171 $total = array_sum($selections);
172
173 if ($total) {
174 // mode
175 $mode_nr = max($selections);
176 $tmp_mode = $selections;
177 asort($tmp_mode, SORT_NUMERIC);
178 $mode = array_keys($tmp_mode, $mode_nr);
179 $a_results->setMode($mode, $mode_nr);
180
181 if (!$has_multi) {
182 // median
183 ksort($selections, SORT_NUMERIC);
184 $median = array();
185 foreach ($selections as $value => $count) {
186 for ($i = 0; $i < $count; $i++) {
187 $median[] = $value;
188 }
189 }
190 if ($total % 2 == 0) {
191 $lower = $median[($total / 2) - 1];
192 $upper = $median[($total / 2)];
193 $median_value = 0.5 * ($lower + $upper);
194 if ($a_categories &&
195 round($median_value) != $median_value) {
196 // mapping calculated value to scale values
197 $median_value = array($lower, $upper);
198 }
199 } else {
200 $median_value = $median[(($total + 1) / 2) - 1];
201 }
202 $a_results->setMedian($median_value);
203 }
204 }
205
206 if ($a_categories) {
207 // selections by category
208 for ($c = 0; $c < $a_categories->getCategoryCount(); $c++) {
209 $cat = $a_categories->getCategory($c);
210 $scale = $cat->scale;
211
213 $cat,
214 $selections[$scale],
215 $total
216 ? $selections[$scale] / $total
217 : null
218 );
219 $a_results->addVariable($var);
220 }
221 }
222 }
223
224 public function parseUserSpecificResults($a_qres, $a_user_id)
225 {
226 $parsed_results = array();
227
228 if (is_array($a_qres)) {
229 foreach ($a_qres as $row_idx => $row_results) {
230 $row_title = $row_results[0];
231 $user_results = $row_results[1]->getUserResults($a_user_id);
232 if ($user_results) {
233 foreach ($user_results as $item) {
234 // :TODO: layout
235 $tmp = $row_title . ": ";
236 if ($item[0] !== "") {
237 $tmp .= $item[0];
238 }
239 if ($item[1] && $item[0]) {
240 $tmp .= ", \"" . nl2br($item[1]) . "\"";
241 } elseif ($item[1]) {
242 $tmp .= "\"" . nl2br($item[1]) . "\"";
243 }
244 $parsed_results[$row_idx . "-" . $item[2]] = $tmp;
245 }
246 }
247 }
248 } else {
249 $user_results = $a_qres->getUserResults($a_user_id);
250 if ($user_results) {
251 foreach ($user_results as $item) {
252 // :TODO: layout
253 if ($item[0] !== "") {
254 $tmp = $item[0];
255 }
256 if ($item[1] && $item[0]) {
257 $tmp .= ", \"" . nl2br($item[1]) . "\"";
258 } elseif ($item[1]) {
259 $tmp = "\"" . nl2br($item[1]) . "\"";
260 }
261 $parsed_results[$item[2]] = $tmp;
262 }
263 }
264 }
265
266 return $parsed_results;
267 }
268
269
270 //
271 // DETAILS
272 //
273
282 public function getGrid($a_results, $a_abs = true, $a_perc = true)
283 {
285
286 if ((bool) $a_abs && (bool) $a_perc) {
287 $cols = array(
288 $lng->txt("category_nr_selected"),
289 $lng->txt("svy_fraction_of_selections")
290 );
291 } elseif ((bool) $a_abs) {
292 $cols = array(
293 $lng->txt("category_nr_selected")
294 );
295 } else {
296 $cols = array(
297 $lng->txt("svy_fraction_of_selections")
298 );
299 }
300
301 $res = array(
302 "cols" => $cols,
303 "rows" => array()
304 );
305
306 $vars = $a_results->getVariables();
307 if ($vars) {
308 foreach ($vars as $var) {
309 $perc = $var->perc
310 ? sprintf("%.2f", $var->perc * 100) . "%"
311 : "0%";
312
313 if ((bool) $a_abs && (bool) $a_perc) {
314 $res["rows"][] = array(
315 $var->cat->title,
316 $var->abs,
317 $perc
318 );
319 } elseif ((bool) $a_abs) {
320 $res["rows"][] = array(
321 $var->cat->title,
322 $var->abs
323 );
324 } else {
325 $res["rows"][] = array(
326 $var->cat->title,
327 $perc
328 );
329 }
330 }
331 }
332
333 return $res;
334 }
335
342 public function getTextAnswers($a_results)
343 {
344 return $a_results->getMappedTextAnswers();
345 }
346
347 protected function getChartColors()
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
375 public function getChart($a_results)
376 {
377 $chart = ilChart::getInstanceByType(ilChart::TYPE_GRID, $a_results->getQuestion()->getId());
378 $chart->setYAxisToInteger(true);
379
380 $colors = $this->getChartColors();
381 $chart->setColors($colors);
382
383 // :TODO:
384 $chart->setsize($this->chart_width, $this->chart_height);
385
386 $vars = $a_results->getVariables();
387
388 $legend = $labels = array();
389 foreach ($vars as $idx => $var) {
390 $data = $chart->getDataInstance(ilChartGrid::DATA_BARS);
391 $data->setBarOptions(0.5, "center");
392 $data->setFill(1);
393 $chart->addData($data);
394
395 // labels
396 $labels[$idx] = "";
397 $legend[] = array(
398 $var->cat->title,
399 $colors[$idx]
400 );
401 $data->setLabel($var->cat->title);
402
403 $data->addPoint($idx, $var->abs);
404 }
405
406 $chart->setTicks($labels, false, true);
407
408 return array(
409 $chart->getHTML(),
410 $legend
411 );
412 }
413
414
415 //
416 // USER-SPECIFIC
417 //
418
424 public function getSkippedValue()
425 {
427 }
428
429
430 //
431 // HELPER
432 //
433
434 protected function getSurveyId()
435 {
437
438 // #18968
439 $set = $ilDB->query("SELECT survey_fi" .
440 " FROM svy_svy_qst" .
441 " WHERE question_fi = " . $ilDB->quote($this->question->getId(), "integer"));
442 $row = $ilDB->fetchAssoc($set);
443 return $row["survey_fi"];
444 }
445
446
452 protected function getNrOfParticipants()
453 {
455
456 if (is_array($this->finished_ids)) {
457 return sizeof($this->finished_ids);
458 }
459
460 $set = $ilDB->query("SELECT finished_id FROM svy_finished" .
461 " WHERE survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer"));
462 return $set->numRows();
463 }
464
465 protected function getAnswerData()
466 {
468
469 $res = array();
470
471 $sql = "SELECT svy_answer.* FROM svy_answer" .
472 " JOIN svy_finished ON (svy_finished.finished_id = svy_answer.active_fi)" .
473 " WHERE svy_answer.question_fi = " . $ilDB->quote($this->question->getId(), "integer") .
474 " AND svy_finished.survey_fi = " . $ilDB->quote($this->getSurveyId(), "integer");
475 if (is_array($this->finished_ids)) {
476 $sql .= " AND " . $ilDB->in("svy_finished.finished_id", $this->finished_ids, "", "integer");
477 }
478 $set = $ilDB->query($sql);
479 while ($row = $ilDB->fetchAssoc($set)) {
480 $res[(int) $row["rowvalue"]][(int) $row["active_fi"]][] = array(
481 "value" => $row["value"],
482 "text" => $row["textanswer"]
483 );
484 }
485
486 return $res;
487 }
488
489
490 //
491 // EXPORT
492 //
493
494 public function exportResults($a_results, $a_do_title, $a_do_label)
495 {
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
535 public function getExportGrid($a_results)
536 {
538
539 $res = array(
540 "cols" => array(
541 $lng->txt("title"),
542 $lng->txt("value"),
543 $lng->txt("category_nr_selected"),
544 $lng->txt("svy_fraction_of_selections")
545 ),
546 "rows" => array()
547 );
548
549 $vars = $a_results->getVariables();
550 if ($vars) {
551 foreach ($vars as $var) {
552 $res["rows"][] = array(
553 $var->cat->title,
554 $var->cat->scale,
555 $var->abs,
556 $var->perc
557 ? sprintf("%.2f", $var->perc * 100) . "%"
558 : "0%"
559 );
560 }
561 }
562
563 return $res;
564 }
565
574 public function getUserSpecificVariableTitles(array &$a_title_row, array &$a_title_row2, $a_do_title, $a_do_label)
575 {
576 // type-specific
577 }
578
586 abstract public function addUserSpecificResults(array &$a_row, $a_user_id, $a_results);
587}
$total
Definition: Utf8Test.php:87
An exception for terminatinating execution or to throw for unit testing.
Class SurveyCategories.
__construct(SurveyQuestion $a_question, array $a_finished_ids=null)
Constructor.
getSkippedValue()
Get caption for skipped value.
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.
getSumScores()
Get sum score for this question for all active ids of run.
addUserSpecificResults(array &$a_row, $a_user_id, $a_results)
exportResults($a_results, $a_do_title, $a_do_label)
getUserSpecificVariableTitles(array &$a_title_row, array &$a_title_row2, $a_do_title, $a_do_label)
Get title columns for user-specific export.
getGrid($a_results, $a_abs=true, $a_perc=true)
Get grid data.
getTextAnswers($a_results)
Get text answers.
getNrOfParticipants()
Returns the number of participants for a survey.
Basic class for all survey question types.
static _getQuestionTypeName($type_tag)
Return the translation for a given question type tag.
static getInstanceByType($a_type, $a_id)
Get type instance.
const TYPE_GRID
static getSurveySkippedValue()
Survey category class.
setMode($a_value, $a_nr_of_selections)
addVariable(ilSurveyEvaluationResultsVariable $a_variable)
addAnswer(ilSurveyEvaluationResultsAnswer $a_answer)
$c
Definition: cli.php:37
global $DIC
Definition: goto.php:24
$i
Definition: metadata.php:24
$results
foreach($_POST as $key=> $value) $res
global $ilDB
$data
Definition: storeScorm.php:23
$cols
Definition: xhr_table.php:11