SurveyUtil::displaySurveyListForDrh()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 26
nc 2
nop 0
dl 0
loc 35
rs 9.504
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AbstractResource;
6
use Chamilo\CoreBundle\Entity\Course;
7
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
8
use Chamilo\CoreBundle\Entity\User;
9
use Chamilo\CoreBundle\Framework\Container;
10
use Chamilo\CourseBundle\Entity\CGroup;
11
use Chamilo\CourseBundle\Entity\CSurvey;
12
use Chamilo\CourseBundle\Entity\CSurveyAnswer;
13
use Chamilo\CourseBundle\Entity\CSurveyInvitation;
14
use Chamilo\CourseBundle\Entity\CSurveyQuestion;
15
use Chamilo\CourseBundle\Entity\CSurveyQuestionOption;
16
use ChamiloSession as Session;
17
use Chamilo\CoreBundle\Component\Utils\ActionIcon;
18
use Chamilo\CoreBundle\Component\Utils\ToolIcon;
19
use Chamilo\CoreBundle\Component\Utils\ObjectIcon;
20
use Chamilo\CoreBundle\Component\Utils\StateIcon;
21
22
/**
23
 * This class offers a series of general utility functions for survey querying and display.
24
 */
25
class SurveyUtil
26
{
27
    /**
28
     * Checks whether the given survey has a pagebreak question as the first
29
     * or the last question.
30
     * If so, break the current process, displaying an error message.
31
     *
32
     * @param int  $survey_id Survey ID (database ID)
33
     * @param bool $continue  Optional. Whether to continue the current
34
     *                        process or exit when breaking condition found. Defaults to true (do not break).
35
     */
36
    public static function check_first_last_question($survey_id, $continue = true)
37
    {
38
        // Table definitions
39
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
40
        $course_id = api_get_course_int_id();
41
        $survey_id = (int) $survey_id;
42
43
        // Getting the information of the question
44
        $sql = "SELECT * FROM $tbl_survey_question
45
                WHERE survey_id='".$survey_id."'
46
                ORDER BY sort ASC";
47
        $result = Database::query($sql);
48
        $total = Database::num_rows($result);
49
        $counter = 1;
50
        $error = false;
51
        while ($row = Database::fetch_assoc($result)) {
52
            if (1 == $counter && 'pagebreak' === $row['type']) {
53
                echo Display::return_message(get_lang('The page break cannot be the first'), 'error', false);
54
                $error = true;
55
            }
56
            if ($counter == $total && 'pagebreak' === $row['type']) {
57
                echo Display::return_message(get_lang('The page break cannot be the last one'), 'error', false);
58
                $error = true;
59
            }
60
            $counter++;
61
        }
62
63
        if (!$continue && $error) {
64
            Display::display_footer();
65
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
66
        }
67
    }
68
69
    /**
70
     * This function removes an (or multiple) answer(s) of a user on a question of a survey.
71
     *
72
     * @param mixed   The user id or email of the person who fills the survey
73
     * @param int The survey id
74
     * @param int The question id
75
     * @param int The option id
76
     *
77
     * @author Patrick Cool <[email protected]>, Ghent University
78
     *
79
     * @version January 2007
80
     */
81
    public static function remove_answer($user, $survey_id, $question_id, $lpItemId = 0): void
82
    {
83
        $sessionId = api_get_session_id();
84
        // table definition
85
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
86
87
        $lpItemCondition = '';
88
        if (!empty($lpItemId)) {
89
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
90
        }
91
        $sessionCondition = '';
92
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
93
            $sessionCondition = api_get_session_condition($sessionId);
94
        }
95
96
        $sql = "DELETE FROM $table
97
				WHERE
98
                    user = '".Database::escape_string($user)."' AND
99
                    survey_id = '".intval($survey_id)."' AND
100
                    question_id = '".intval($question_id)."'
101
                    $sessionCondition
102
                    $lpItemCondition";
103
        Database::query($sql);
104
    }
105
106
    public static function saveAnswer(
107
        $user,
108
        CSurvey $survey,
109
        CSurveyQuestion $question,
110
        $optionId,
111
        $optionValue,
112
        $otherOption = '',
113
        $lpItemId = 0
114
    ): bool {
115
116
        // Make the survey anonymous
117
        if (1 == $survey->getAnonymous()) {
118
            $surveyUser = Session::read('surveyuser');
119
            if (empty($surveyUser)) {
120
                $user = md5($user.time());
121
                Session::write('surveyuser', $user);
122
            } else {
123
                $user = Session::read('surveyuser');
124
            }
125
        }
126
127
        if (!empty($otherOption)) {
128
            $optionId = $optionId.'@:@'.$otherOption;
129
        }
130
131
        $sessionId = api_get_session_id();
132
        $answer = new CSurveyAnswer();
133
        $answer
134
            ->setUser($user)
135
            ->setSurvey($survey)
136
            ->setQuestion($question)
137
            ->setOptionId($optionId)
138
            ->setValue((int) $optionValue)
139
            ->setLpItemId((int) $lpItemId)
140
            ->setSessionId($sessionId ?: null)
141
        ;
142
143
        $em = Database::getManager();
144
        $em->persist($answer);
145
        $em->flush();
146
147
        $insertId = $answer->getIid();
148
        if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
149
            return true;
150
        }
151
152
        return false;
153
    }
154
155
    /**
156
     * This function checks the parameters that are used in this page.
157
     *
158
     * @return string $people_filled The header, an error and the footer if any parameter fails, else it returns true
159
     *
160
     * @author Patrick Cool <[email protected]>, Ghent University
161
     *
162
     * @version February 2007
163
     */
164
    public static function check_parameters($people_filled)
165
    {
166
        $error = false;
167
168
        // Getting the survey data
169
        $survey_data = SurveyManager::get_survey($_GET['survey_id']);
170
171
        // $_GET['survey_id'] has to be numeric
172
        if (!is_numeric($_GET['survey_id'])) {
173
            $error = get_lang('Unknown survey id');
174
        }
175
176
        // $_GET['action']
177
        $allowed_actions = [
178
            'overview',
179
            'questionreport',
180
            'userreport',
181
            'comparativereport',
182
            'completereport',
183
            'deleteuserreport',
184
        ];
185
        if (isset($_GET['action']) && !in_array($_GET['action'], $allowed_actions)) {
186
            $error = get_lang('Action not allowed');
187
        }
188
189
        // User report
190
        if (isset($_GET['action']) && 'userreport' == $_GET['action']) {
191
            if (0 == $survey_data['anonymous']) {
192
                foreach ($people_filled as $key => &$value) {
193
                    $people_filled_userids[] = $value['invited_user'];
194
                }
195
            } else {
196
                $people_filled_userids = $people_filled;
197
            }
198
199
            if (isset($_GET['user']) && !in_array($_GET['user'], $people_filled_userids)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $people_filled_userids does not seem to be defined for all execution paths leading up to this point.
Loading history...
200
                $error = get_lang('Unknow user');
201
            }
202
        }
203
204
        // Question report
205
        if (isset($_GET['action']) && 'questionreport' == $_GET['action']) {
206
            if (isset($_GET['question']) && !is_numeric($_GET['question'])) {
207
                $error = get_lang('Unknown question');
208
            }
209
        }
210
211
        if ($error) {
212
            $tool_name = get_lang('Reporting');
213
            Display::addFlash(
214
                Display::return_message(
215
                    get_lang('Error').': '.$error,
216
                    'error',
217
                    false
218
                )
219
            );
220
            Display::display_header($tool_name);
221
            Display::display_footer();
222
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
223
        }
224
225
        return true;
226
    }
227
228
    public static function handleReportingActions(CSurvey $survey, array $people_filled = [])
229
    {
230
        $action = $_GET['action'] ?? '';
231
232
        switch ($action) {
233
            case 'questionreport':
234
                self::display_question_report($survey);
235
                break;
236
            case 'userreport':
237
                self::displayUserReport($survey, $people_filled);
238
                break;
239
            case 'comparativereport':
240
                self::display_comparative_report();
241
                break;
242
            case 'completereport':
243
                $surveysAnswered = SurveyManager::getInvitationsAnswered($survey->getCode(), api_get_course_int_id(), api_get_session_id());
244
                if (count($surveysAnswered) > 0) {
245
                    foreach ($surveysAnswered as $survey) {
246
                        echo self::displayCompleteReport($survey, 0, true, true, !$survey->getAnonymous(), $survey->getLpItemId());
247
                    }
248
                }
249
                break;
250
            case 'deleteuserreport':
251
                self::delete_user_report($survey->getIid(), $_GET['user']);
252
                break;
253
        }
254
    }
255
256
    /**
257
     * This function deletes the report of an user who wants to retake the survey.
258
     *
259
     * @param int $survey_id
260
     * @param int $user_id
261
     *
262
     * @author Christian Fasanando Flores <[email protected]>
263
     *
264
     * @version November 2008
265
     */
266
    public static function delete_user_report($survey_id, $user_id)
267
    {
268
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
269
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
270
        $table_survey = Database::get_course_table(TABLE_SURVEY);
271
272
        $course_id = api_get_course_int_id();
273
        $survey_id = (int) $survey_id;
274
        $user_id = Database::escape_string($user_id);
275
276
        if (!empty($survey_id) && !empty($user_id)) {
277
278
            $sessionCondition = '';
279
            if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
280
                $sessionId = api_get_session_id();
281
                $sessionCondition = api_get_session_condition($sessionId);
282
            }
283
284
            // delete data from survey_answer by user_id and survey_id
285
            $sql = "DELETE FROM $table_survey_answer
286
			        WHERE c_id = $course_id AND survey_id = '".$survey_id."' AND user = '".$user_id."' $sessionCondition";
287
            Database::query($sql);
288
            // update field answered from survey_invitation by user_id and survey_id
289
            $sql = "UPDATE $table_survey_invitation SET answered = '0'
290
			        WHERE
291
			            c_id = $course_id AND
292
			            survey_id = (
293
                            SELECT iid FROM $table_survey
294
                            WHERE
295
                                iid = '".$survey_id."'
296
                        ) AND
297
			            user_id = '".$user_id."'  $sessionCondition";
298
            $result = Database::query($sql);
299
        }
300
301
        if (false !== $result) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
302
            $message = get_lang('The user\'s answers to the survey have been succesfully removed.').'<br />
303
					<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
304
                .$survey_id.'">'.
305
                get_lang('Go back').'</a>';
306
            echo Display::return_message($message, 'confirmation', false);
307
        }
308
    }
309
310
    /**
311
     * @return string
312
     */
313
    public static function displayUserReportForm(CSurvey $survey, array $people_filled = [])
314
    {
315
        $surveyId = $survey->getIid();
316
        // Step 1: selection of the user
317
        echo "<script>
318
        function jumpMenu(targ,selObj,restore) {
319
            eval(targ+\".location='\"+selObj.options[selObj.selectedIndex].value+\"'\");
320
            if (restore) selObj.selectedIndex=0;
321
        }
322
		</script>";
323
        echo get_lang('Select user who filled the survey').'<br />';
324
        echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
325
        echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
326
            .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
327
            .get_lang('User').'</option>';
328
329
        foreach ($people_filled as $key => &$person) {
330
            if (0 == $survey->getAnonymous()) {
331
                $name = $person['user_info']['complete_name_with_username'];
332
                $id = $person['user_id'];
333
                if ('' == $id) {
334
                    $id = $person['invited_user'];
335
                    $name = $person['invited_user'];
336
                }
337
            } else {
338
                $name = get_lang('Anonymous').' '.($key + 1);
339
                $id = $person;
340
            }
341
            echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
342
                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&user='
343
                .Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
344
            if (isset($_GET['user']) && $_GET['user'] == $id) {
345
                echo 'selected="selected"';
346
            }
347
            echo '>'.$name.'</option>';
348
        }
349
        echo '</select>';
350
    }
351
352
    /**
353
     * @param int   $userId
354
     * @param array $survey_data
355
     * @param bool  $addMessage
356
     */
357
    public static function displayUserReportAnswers($userId, CSurvey $survey, $addMessage = true)
358
    {
359
        // Database table definitions
360
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
361
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
362
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
363
        $course_id = api_get_course_int_id();
364
        $surveyId = $survey->getIid();
365
        $userId = Database::escape_string($userId);
366
367
        $content = '';
368
        // Step 2: displaying the survey and the answer of the selected users
369
        if (!empty($userId)) {
370
            if ($addMessage) {
371
                $content .= Display::return_message(
372
                    get_lang('This screen displays an exact copy of the form as it was filled by the user'),
373
                    'normal',
374
                    false
375
                );
376
            }
377
378
            // Getting all the questions and options
379
            $sql = "SELECT
380
			            survey_question.iid question_id,
381
			            survey_question.survey_id,
382
			            survey_question.survey_question,
383
			            survey_question.display,
384
			            survey_question.max_value,
385
			            survey_question.sort,
386
			            survey_question.type,
387
                        survey_question_option.iid question_option_id,
388
                        survey_question_option.option_text,
389
                        survey_question_option.sort as option_sort
390
					FROM $table_survey_question survey_question
391
					LEFT JOIN $table_survey_question_option survey_question_option
392
					ON
393
					    survey_question.iid = survey_question_option.question_id
394
					WHERE
395
					    survey_question NOT LIKE '%{{%' AND
396
					    survey_question.survey_id = '".$surveyId."'
397
					ORDER BY survey_question.sort, survey_question_option.sort ASC";
398
            $result = Database::query($sql);
399
            while ($row = Database::fetch_assoc($result)) {
400
                if ('pagebreak' !== $row['type']) {
401
                    $questions[$row['sort']]['question_id'] = $row['question_id'];
402
                    $questions[$row['sort']]['survey_id'] = $row['survey_id'];
403
                    $questions[$row['sort']]['survey_question'] = $row['survey_question'];
404
                    $questions[$row['sort']]['display'] = $row['display'];
405
                    $questions[$row['sort']]['type'] = $row['type'];
406
                    $questions[$row['sort']]['maximum_score'] = $row['max_value'];
407
                    $questions[$row['sort']]['options'][$row['question_option_id']] = $row['option_text'];
408
                }
409
            }
410
411
            $sessionCondition = '';
412
            if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
413
                $sessionId = api_get_session_id();
414
                $sessionCondition = api_get_session_condition($sessionId);
415
            }
416
417
            // Getting all the answers of the user
418
            $sql = "SELECT * FROM $table_survey_answer
419
			        WHERE
420
                        survey_id = '".$surveyId."' AND
421
                        user = '".$userId."' $sessionCondition";
422
            $result = Database::query($sql);
423
            while ($row = Database::fetch_assoc($result)) {
424
                $answers[$row['question_id']][] = $row['option_id'];
425
                $all_answers[$row['question_id']][] = $row;
426
            }
427
428
            // Displaying all the questions
429
            foreach ($questions as &$question) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $questions does not seem to be defined for all execution paths leading up to this point.
Loading history...
430
                // If the question type is a scoring then we have to format the answers differently
431
                switch ($question['type']) {
432
                    case 'score':
433
                        $finalAnswer = [];
434
                        if (is_array($question) && is_array($all_answers)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $all_answers does not seem to be defined for all execution paths leading up to this point.
Loading history...
435
                            foreach ($all_answers[$question['question_id']] as $key => &$answer_array) {
436
                                $finalAnswer[$answer_array['option_id']] = $answer_array['value'];
437
                            }
438
                        }
439
                        break;
440
                    case 'multipleresponse':
441
                        $finalAnswer = isset($answers[$question['question_id']]) ? $answers[$question['question_id']] : '';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $answers does not seem to be defined for all execution paths leading up to this point.
Loading history...
442
                        break;
443
                    default:
444
                        $finalAnswer = '';
445
                        if (isset($all_answers[$question['question_id']])) {
446
                            $finalAnswer = $all_answers[$question['question_id']][0]['option_id'];
447
                        }
448
                        break;
449
                }
450
451
                $display = survey_question::createQuestion($question['type']);
452
                $url = api_get_self();
453
                $form = new FormValidator('question', 'post', $url);
454
                $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
455
                $form->addHtml($question['survey_question']);
456
                $display->render($form, $question, $finalAnswer);
457
                $form->addHtml('</div></div>');
458
                $content .= $form->returnForm();
459
            }
460
        }
461
462
        return $content;
463
    }
464
465
    /**
466
     * This function displays the user report which is basically nothing more
467
     * than a one-page display of all the questions
468
     * of the survey that is filled with the answers of the person who filled the survey.
469
     *
470
     * @return string html code of the one-page survey with the answers of the selected user
471
     *
472
     * @author Patrick Cool <[email protected]>, Ghent University
473
     *
474
     * @version February 2007 - Updated March 2008
475
     */
476
    public static function displayUserReport(CSurvey $survey, $people_filled, $addActionBar = true)
477
    {
478
        $surveyId = $survey->getIid();
479
        $reportingUrl = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
480
481
        // Actions bar
482
        if ($addActionBar) {
483
            $actions = '<a href="'.$reportingUrl.'">'.
484
                Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'))
485
                .'</a>';
486
            if (isset($_GET['user'])) {
487
                if (api_is_allowed_to_edit()) {
488
                    // The delete link
489
                    $actions .= '<a
490
                        href="'.$reportingUrl.'&action=deleteuserreport&user='.Security::remove_XSS($_GET['user']).'" >'.
491
                        Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Delete')).'</a>';
492
                }
493
494
                // Export the user report
495
                $actions .= '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
496
                    .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a> ';
497
                $actions .= '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
498
                    .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a> ';
499
                $actions .= '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
500
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
501
                    .Security::remove_XSS($_GET['user']).'">';
502
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
503
                $actions .= '<input type="hidden" name="export_format" value="csv">';
504
                $actions .= '</form>';
505
                $actions .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
506
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
507
                    .Security::remove_XSS($_GET['user']).'">';
508
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
509
                $actions .= '<input type="hidden" name="export_format" value="xls">';
510
                $actions .= '</form>';
511
                $actions .= '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
512
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
513
            }
514
            echo Display::toolbarAction('survey', [$actions]);
515
        }
516
517
        echo self::displayUserReportForm($survey, $people_filled);
518
        if (isset($_GET['user'])) {
519
            echo self::displayUserReportAnswers($_GET['user'], $survey);
520
        }
521
    }
522
523
    /**
524
     * This function displays the report by question.
525
     *
526
     * It displays a table with all the options of the question and the number of users who have answered positively on
527
     * the option. The number of users who answered positive on a given option is expressed in an absolute number, in a
528
     * percentage of the total and graphically using bars By clicking on the absolute number you get a list with the
529
     * persons who have answered this. You can then click on the name of the person and you will then go to the report
530
     * by user where you see all the answers of that user.
531
     *
532
     * @return string html code that displays the report by question
533
     *
534
     * @todo allow switching between horizontal and vertical.
535
     * @todo multiple response: percentage are probably not OK
536
     * @todo the question and option text have to be shortened and should expand when the user clicks on it.
537
     * @todo the pagebreak and comment question types should not be shown => removed from $survey_data before
538
     *
539
     * @author Patrick Cool <[email protected]>, Ghent University
540
     *
541
     * @version February 2007 - Updated March 2008
542
     */
543
    public static function display_question_report(CSurvey $survey)
544
    {
545
        $singlePage = isset($_GET['single_page']) ? (int) $_GET['single_page'] : 0;
546
        // Determining the offset of the sql statement (the n-th question of the survey)
547
        $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question'];
548
        $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0;
549
        $surveyId = $survey->getIid();
550
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
551
        $course_id = api_get_course_int_id();
552
553
        $sessionCondition = '';
554
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
555
            $sessionId = api_get_session_id();
556
            $sessionCondition = api_get_session_condition($sessionId);
557
        }
558
559
        // Database table definitions
560
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
561
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
562
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
563
564
        $actions = '<a
565
            href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'.
566
            Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
567
                '',
568
                ICON_SIZE_MEDIUM
569
            ).'</a>';
570
        $actions .= Display::url(
571
            Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportToPdf')),
572
            'javascript: void(0);',
573
            ['onclick' => 'exportToPdf();']
574
        );
575
576
        echo Display::toolbarAction('survey', [$actions]);
577
578
        $fromUntil = sprintf(
579
            get_lang('FromXUntilY'),
580
            api_get_local_time($survey->getAvailFrom()),
581
            api_get_local_time($survey->getAvailTill())
582
        );
583
        $max = 80;
584
        $data = [
585
            get_lang('SurveyTitle') => cut(strip_tags($survey->getTitle()), $max),
586
            get_lang('SurveySubTitle') => cut(strip_tags($survey->getSubtitle()), $max),
587
            get_lang('Dates') => $fromUntil,
588
            get_lang('SurveyIntroduction') => cut(strip_tags($survey->getIntro()), $max),
589
        ];
590
591
        $table = new HTML_Table(['id' => 'pdf_table', 'class' => 'table']);
592
        $row = 0;
593
        foreach ($data as $label => $item) {
594
            $table->setCellContents($row, 0, $label);
595
            $table->setCellContents($row, 1, $item);
596
            $row++;
597
        }
598
599
        $questions = $survey->getQuestions();
600
        $numberOfQuestions = 0;
601
        foreach ($questions as $question) {
602
            if ('pagebreak' !== $question->getType()) {
603
                $numberOfQuestions++;
604
            }
605
        }
606
607
        $newQuestionList = [];
608
        if ($numberOfQuestions > 0) {
609
            $limitStatement = null;
610
            if (!$singlePage) {
611
                echo '<div id="question_report_questionnumbers" class="pagination">';
612
                if (0 != $currentQuestion) {
613
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
614
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset - 1).'">'
615
                        .get_lang('Previous question').'</a></li>';
616
                }
617
618
                for ($i = 1; $i <= $numberOfQuestions; $i++) {
619
                    if ($offset != $i - 1) {
620
                        echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
621
                            .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($i - 1).'">'.$i.'</a></li>';
622
                    } else {
623
                        echo '<li class="disabled"s><a href="#">'.$i.'</a></li>';
624
                    }
625
                }
626
                if ($currentQuestion < ($numberOfQuestions - 1)) {
627
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
628
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset + 1).'">'
629
                        .get_lang('Next question').'</li></a>';
630
                }
631
                echo '</ul>';
632
                echo '</div>';
633
                $limitStatement = " LIMIT $offset, 1";
634
            }
635
636
            // Getting the question information
637
            /*$sql = "SELECT * FROM $table_survey_question
638
                    WHERE
639
                        survey_id = $surveyId AND
640
                        survey_question NOT LIKE '%{{%' AND
641
                        type <>'pagebreak'
642
                    ORDER BY sort ASC
643
                    $limitStatement";
644
            $result = Database::query($sql);
645
            while ($row = Database::fetch_array($result)) {*/
646
            foreach ($questions as $question) {
647
                if (strpos($question->getSurveyQuestion(), '%{{%') && 'pagebreak' !== $question->getType()) {
648
                    continue;
649
                }
650
                $newQuestionList[$question->getIid()] = $question;
651
            }
652
        }
653
        echo '<div id="question_results">';
654
        /** @var CSurveyQuestion $question */
655
        foreach ($newQuestionList as $question) {
656
            $chartData = [];
657
            $options = [];
658
            $questionId = $question->getIid();
659
660
            echo '<div class="question-item">';
661
            echo '<div class="title-question">';
662
            echo strip_tags($question->getSurveyQuestion());
663
            echo '</div>';
664
            $type = $question->getType();
665
666
            if ('score' === $type) {
667
                /** @todo This function should return the options as this is needed further in the code */
668
                $options = self::display_question_report_score($survey, $question, $offset);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $options is correct as self::display_question_r...ey, $question, $offset) targeting SurveyUtil::display_question_report_score() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
669
            } elseif ('open' === $type || 'comment' === $type) {
670
                echo '<div class="open-question">';
671
                /** @todo Also get the user who has answered this */
672
                $sql = "SELECT * FROM $table_survey_answer
673
                        WHERE
674
                            survey_id= $surveyId AND
675
                            question_id = $questionId ";
676
                $result = Database::query($sql);
677
                while ($row = Database::fetch_assoc($result)) {
678
                    echo $row['option_id'].'<hr noshade="noshade" size="1" />';
679
                }
680
                echo '</div>';
681
            } else {
682
                // Getting the options ORDER BY sort ASC
683
                $sql = "SELECT * FROM $table_survey_question_option
684
                        WHERE
685
                            survey_id = $surveyId AND
686
                            question_id = $questionId
687
                        ORDER BY sort ASC";
688
                $result = Database::query($sql);
689
                while ($row = Database::fetch_assoc($result)) {
690
                    $options[$row['iid']] = $row;
691
                }
692
                // Getting the answers
693
                $sql = "SELECT *, count(iid) as total
694
                        FROM $table_survey_answer
695
                        WHERE
696
                            survey_id = $surveyId AND
697
                            question_id = $questionId
698
                        GROUP BY option_id, value";
699
                $result = Database::query($sql);
700
                $number_of_answers = [];
701
                $data = [];
702
                while ($row = Database::fetch_assoc($result)) {
703
                    if (!isset($number_of_answers[$row['question_id']])) {
704
                        $number_of_answers[$row['question_id']] = 0;
705
                    }
706
                    $number_of_answers[$row['question_id']] += $row['total'];
707
                    if ('multiplechoiceother' === $type) {
708
                        $parts = ch_multiplechoiceother::decodeOptionValue($row['option_id']);
709
                        $row['option_id'] = $parts[0];
710
                    }
711
                    $data[$row['option_id']] = $row;
712
                }
713
714
                foreach ($options as $option) {
715
                    $optionText = strip_tags($option['option_text']);
716
                    $optionText = html_entity_decode($optionText);
717
                    $votes = 0;
718
                    if (isset($data[$option['iid']]['total'])) {
719
                        $votes = $data[$option['iid']]['total'];
720
                    }
721
                    array_push($chartData, ['option' => $optionText, 'votes' => $votes]);
722
                }
723
                $chartContainerId = 'chartContainer'.$questionId;
724
                echo '<div id="'.$chartContainerId.'" style="text-align:center;">';
725
                echo self::drawChart($chartData, false, $chartContainerId, false);
726
                echo '</div>';
727
728
                // displaying the table: headers
729
                echo '<table class="display-survey table" id="table_'.$chartContainerId.'">';
730
                echo '';
731
                echo '	<tr>';
732
                echo '		<th style="width: 50%">&nbsp;</th>';
733
                echo '		<th style="width: 10%">'.get_lang('AbsoluteTotal').'</th>';
734
                echo '		<th style="width: 10%">'.get_lang('Percentage').'</th>';
735
                echo '		<th style="width: 30%">'.get_lang('VisualRepresentation').'</th>';
736
                echo '	</tr>';
737
738
                // Displaying the table: the content
739
                if (is_array($options)) {
740
                    foreach ($options as $key => &$value) {
741
                        if ('multiplechoiceother' === $type && 'other' === $value['option_text']) {
742
                            $value['option_text'] = get_lang('SurveyOtherAnswer');
743
                        }
744
745
                        $absolute_number = null;
746
                        if (isset($data[$value['iid']])) {
747
                            $absolute_number = $data[$value['iid']]['total'];
748
                        }
749
                        if ('percentage' === $type && empty($absolute_number)) {
750
                            continue;
751
                        }
752
                        $number_of_answers[$option['question_id']] = isset($number_of_answers[$option['question_id']])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $option does not seem to be defined for all execution paths leading up to this point.
Loading history...
753
                            ? $number_of_answers[$option['question_id']]
754
                            : 0;
755
                        if (0 == $number_of_answers[$option['question_id']]) {
756
                            $answers_number = 0;
757
                        } else {
758
                            $answers_number = $absolute_number / $number_of_answers[$option['question_id']] * 100;
759
                        }
760
                        echo '	<tr>';
761
                        echo '<td>'.$value['option_text'].'</td>';
762
                        echo '<td>';
763
                        if (0 != $absolute_number) {
764
                            echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
765
                                .'&survey_id='.$surveyId.'&question='.$offset.'&viewoption='
766
                                .$value['iid'].'">'.$absolute_number.'</a>';
767
                        } else {
768
                            echo '0';
769
                        }
770
771
                        echo '      </td>';
772
                        echo '<td>'.round($answers_number, 2).' %</td>';
773
                        echo '<td>';
774
                        $size = $answers_number * 2;
775
                        if ($size > 0) {
776
                            echo '<div
777
                                    style="border:1px solid #264269; background-color:#aecaf4; height:10px;
778
                                    width:'.$size.'px">
779
                                    &nbsp;
780
                                    </div>';
781
                        } else {
782
                            echo '<div style="text-align: left;">'.get_lang("No data available").'</div>';
783
                        }
784
                        echo ' </td>';
785
                        echo ' </tr>';
786
                    }
787
                }
788
789
                $optionResult = '';
790
                if (isset($option['question_id']) && isset($number_of_answers[$option['question_id']])) {
791
                    if (0 == $number_of_answers[$option['question_id']]) {
792
                        $optionResult = '0';
793
                    } else {
794
                        $optionResult = $number_of_answers[$option['question_id']];
795
                    }
796
                }
797
798
                // displaying the table: footer (totals)
799
                echo '	<tr>
800
                            <td><b>'.get_lang('Total').'</b></td>
801
                            <td><b>'.$optionResult.'</b></td>
802
                            <td>&nbsp;</td>
803
                            <td>&nbsp;</td>
804
                        </tr>
805
                        </table>';
806
            }
807
            echo '</div>';
808
        }
809
        echo '</div>';
810
811
        // Survey information, needed for the PDF export.
812
        echo Display::page_subheader(get_lang('Survey')).'<br />';
813
        $table->display();
814
815
        if (isset($_GET['viewoption'])) {
816
            echo '<div class="answered-people">';
817
            echo '<h4>'.get_lang('People who have chosen this answer').': '
818
                .strip_tags($options[Security::remove_XSS($_GET['viewoption'])]['option_text']).'</h4>';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $options seems to be defined by a foreach iteration on line 655. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
819
820
            if (is_numeric($_GET['value'])) {
821
                $sql_restriction = "AND value='".Database::escape_string($_GET['value'])."'";
822
            }
823
824
            $sql = "SELECT user FROM $table_survey_answer
825
                    WHERE
826
                        c_id = $course_id AND
827
                        option_id = '".Database::escape_string($_GET['viewoption'])."'
828
                        $sql_restriction $sessionCondition";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sql_restriction does not seem to be defined for all execution paths leading up to this point.
Loading history...
829
            $result = Database::query($sql);
830
            echo '<ul>';
831
            while ($row = Database::fetch_assoc($result)) {
832
                $user_info = api_get_user_info($row['user']);
833
                echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
834
                    .$surveyId.'&user='.$row['user'].'">'
835
                    .$user_info['complete_name_with_username']
836
                    .'</a></li>';
837
            }
838
            echo '</ul>';
839
            echo '</div>';
840
        }
841
    }
842
843
    /**
844
     * Display score data about a survey question.
845
     *
846
     * @param    int    The offset of results shown
847
     */
848
    public static function display_question_report_score(CSurvey $survey, CSurveyQuestion $question, $offset)
849
    {
850
        // Database table definitions
851
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
852
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
853
        $surveyId = $survey->getIid();
854
        $questionId = $question->getIid();
855
        $options = $survey->getOptions();
856
857
        $sessionCondition = '';
858
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
859
            $sessionId = api_get_session_id();
860
            $sessionCondition = api_get_session_condition($sessionId);
861
        }
862
863
        foreach ($options as $option) {
864
            $options[$option->getIid()] = $option;
865
        }
866
867
        // Getting the answers
868
        $sql = "SELECT *, count(iid) as total
869
                FROM $table_survey_answer
870
                WHERE
871
                   survey_id= $surveyId AND
872
                   question_id = '".$questionId."'
873
                   $sessionCondition
874
                GROUP BY option_id, value";
875
        $result = Database::query($sql);
876
        $number_of_answers = 0;
877
        while ($row = Database::fetch_array($result)) {
878
            $number_of_answers += $row['total'];
879
            $data[$row['option_id']][$row['value']] = $row;
880
        }
881
882
        $chartData = [];
883
        /** @var CSurveyQuestionOption $option */
884
        foreach ($options as $option) {
885
            $optionId = $option->getIid();
886
            $optionText = strip_tags($option->getOptionText());
887
            $optionText = html_entity_decode($optionText);
888
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
889
                $votes = null;
890
                if (isset($data[$optionId][$i])) {
891
                    $votes = $data[$optionId][$i]['total'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.
Loading history...
892
                }
893
894
                if (empty($votes)) {
895
                    $votes = '0';
896
                }
897
                array_push(
898
                    $chartData,
899
                    [
900
                        'serie' => $optionText,
901
                        'option' => $i,
902
                        'votes' => $votes,
903
                    ]
904
                );
905
            }
906
        }
907
        echo '<div id="chartContainer" class="col-md-12">';
908
        echo self::drawChart($chartData, true);
909
        echo '</div>';
910
911
        // Displaying the table: headers
912
        echo '<table class="table">';
913
        echo '	<tr>';
914
        echo '		<th>&nbsp;</th>';
915
        echo '		<th>'.get_lang('Score').'</th>';
916
        echo '		<th>'.get_lang('Absolute total').'</th>';
917
        echo '		<th>'.get_lang('Percentage').'</th>';
918
        echo '		<th>'.get_lang('Graphic').'</th>';
919
        echo '	</tr>';
920
        // Displaying the table: the content
921
        foreach ($options as $key => $value) {
922
            $optionId = $value->getIid();
923
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
924
                $absolute_number = null;
925
                if (isset($data[$optionId][$i])) {
926
                    $absolute_number = $data[$optionId][$i]['total'];
927
                }
928
929
                echo '<tr>';
930
                echo '<td>'.$value->getOptionText().'</td>';
931
                echo '<td>'.$i.'</td>';
932
933
                echo '<td><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
934
                    .'&survey_id='.$surveyId.'&question='.Security::remove_XSS($offset)
935
                    .'&viewoption='.$optionId.'&value='.$i.'">'.$absolute_number.'</a></td>';
936
937
                $percentage = 0;
938
                $size = 0;
939
                if (!empty($number_of_answers)) {
940
                    $percentage = round($absolute_number / $number_of_answers * 100, 2);
941
                    $size = ($absolute_number / $number_of_answers * 100 * 2);
942
                }
943
                echo '<td>'.$percentage.' %</td>';
944
                echo '<td>';
945
                if ($size > 0) {
946
                    echo '<div
947
                            style="border:1px solid #264269;
948
                            background-color:#aecaf4;
949
                            height:10px; width:'.$size.'px">
950
                            &nbsp;
951
                        </div>';
952
                }
953
                echo '		</td>';
954
                echo '	</tr>';
955
            }
956
        }
957
        // Displaying the table: footer (totals)
958
        echo '	<tr>';
959
        echo '		<td style="border-top:1px solid black"><b>'.get_lang('Total').'</b></td>';
960
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
961
        echo '		<td style="border-top:1px solid black"><b>'.$number_of_answers.'</b></td>';
962
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
963
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
964
        echo '	</tr>';
965
        echo '</table>';
966
    }
967
968
    /**
969
     * This functions displays the complete reporting.
970
     *
971
     * @param int  $userId
972
     * @param bool $addActionBar
973
     * @param bool $addFilters
974
     * @param bool $addExtraFields
975
     *
976
     * @return string
977
     */
978
    public static function displayCompleteReport(
979
        CSurvey $survey,
980
        $userId = 0,
981
        $addActionBar = true,
982
        $addFilters = true,
983
        $addExtraFields = true,
984
        $lpItemId = 0
985
    ) {
986
        // Database table definitions
987
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
988
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
989
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
990
991
        $surveyId = $survey->getIid();
992
        $course_id = api_get_course_int_id();
993
994
        if (empty($surveyId) || empty($course_id)) {
995
            return '';
996
        }
997
998
        $sessionCondition = '';
999
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
1000
            $sessionId = api_get_session_id();
1001
            $sessionCondition = api_get_session_condition($sessionId);
1002
        }
1003
        $lpItemCondition = '';
1004
        if (!empty($lpItemId)) {
1005
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
1006
        }
1007
1008
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
1009
        $content = '';
1010
        if (!empty($lpItemId)) {
1011
            $tableLp = Database::get_course_table(TABLE_LP_MAIN);
1012
            $tableLpItem = Database::get_course_table(TABLE_LP_ITEM);
1013
            $sql = "SELECT l.name,
1014
                    li.title
1015
                    FROM $tableLpItem li
1016
                    INNER JOIN $tableLp l
1017
                    ON l.iid = li.lp_id AND
1018
                       l.c_id = li.c_id
1019
                    WHERE li.c_id = $course_id AND
1020
                          li.iid = $lpItemId";
1021
            $rs = Database::query($sql);
1022
            if (Database::num_rows($rs) > 0) {
1023
                $row = Database::fetch_assoc($rs);
1024
                $lpName = $row['name'];
1025
                $lpItemTitle = $row['title'];
1026
                $content .= '<h3>'.$lpName.' : '.$lpItemTitle.'</h3>';
1027
            }
1028
        }
1029
1030
        if ($addActionBar) {
1031
            $actions = '<a
1032
                href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
1033
                .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
1034
                    [],
1035
                    ICON_SIZE_MEDIUM
1036
                )
1037
                .'</a>';
1038
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
1039
                .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a>';
1040
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
1041
                .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a>';
1042
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1c.submit();">'
1043
                .Display::getMdiIcon(ActionIcon::EXPORT_ARCHIVE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportAsCompactCSV')).'</a>';
1044
1045
            $content .= Display::toolbarAction('survey', [$actions]);
1046
1047
            // The form
1048
            $content .= '<form
1049
                id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
1050
                .$surveyId.'&'.api_get_cidreq().'">';
1051
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1052
            $content .= '<input type="hidden" name="export_format" value="csv">';
1053
            $content .= '</form>';
1054
            $content .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self(
1055
                ).'?action='.$action.'&survey_id='
1056
                .$surveyId.'&'.api_get_cidreq().'">';
1057
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1058
            $content .= '<input type="hidden" name="export_format" value="xls">';
1059
            $content .= '</form>';
1060
            $content .= '<form id="form1c" name="form1c" method="post" action="'.api_get_self(
1061
                ).'?action='.$action.'&survey_id='
1062
                .$surveyId.'&'.api_get_cidreq().'">';
1063
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1064
            $content .= '<input type="hidden" name="export_format" value="csv-compact">';
1065
            $content .= '</form>';
1066
        }
1067
1068
        $content .= '<form
1069
            id="form2"
1070
            name="form2"
1071
            method="post"
1072
            action="'.api_get_self().'?action='.$action.'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
1073
        $content .= '<br /><table class="table table-hover table-striped data_table" border="1">';
1074
        // Getting the number of options per question
1075
        $content .= '<tr>';
1076
        $content .= '<th>';
1077
1078
        if ($addFilters) {
1079
            if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1080
                (isset($_POST['export_report']) && $_POST['export_report'])
1081
            ) {
1082
                $content .= '<button class="cancel"
1083
                                type="submit"
1084
                                name="reset_question_filter" value="'.get_lang('Reset filter').'">'.
1085
                                get_lang('Reset filter').'</button>';
1086
            }
1087
            $content .= '<button
1088
                            class = "save"
1089
                            type="submit" name="submit_question_filter" value="'.get_lang('Filter').'">'.
1090
                            get_lang('Filter').'</button>';
1091
            $content .= '</th>';
1092
        }
1093
1094
        $display_extra_user_fields = false;
1095
        if ($addExtraFields) {
1096
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1097
                    isset($_POST['export_report']) && $_POST['export_report']) ||
1098
                !empty($_POST['fields_filter'])
1099
            ) {
1100
                // Show user fields section with a big th colspan that spans over all fields
1101
                $extra_user_fields = UserManager::get_extra_fields(
1102
                    0,
1103
                    0,
1104
                    5,
1105
                    'ASC',
1106
                    false,
1107
                    true
1108
                );
1109
                $num = count($extra_user_fields);
1110
                if ($num > 0) {
1111
                    $content .= '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
1112
                    $content .= '<label>';
1113
                    if ($addFilters) {
1114
                        $content .= '<input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
1115
                    }
1116
                    $content .= get_lang('Profile attributes');
1117
                    $content .= '</label>';
1118
                    $content .= '</th>';
1119
                    $display_extra_user_fields = true;
1120
                }
1121
            }
1122
        }
1123
1124
        $sql = "SELECT
1125
                  q.iid question_id,
1126
                  q.type,
1127
                  q.survey_question,
1128
                  count(o.iid) as number_of_options
1129
				FROM $table_survey_question q
1130
				LEFT JOIN $table_survey_question_option o
1131
				ON q.iid = o.question_id
1132
				WHERE
1133
				    survey_question NOT LIKE '%{{%' AND
1134
				    q.survey_id = '".$surveyId."'
1135
				GROUP BY q.iid
1136
				ORDER BY q.sort ASC";
1137
        $result = Database::query($sql);
1138
        $questions = [];
1139
        while ($row = Database::fetch_array($result)) {
1140
            // We show the questions if
1141
            // 1. there is no question filter and the export button has not been clicked
1142
            // 2. there is a quesiton filter but the question is selected for display
1143
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1144
                (is_array($_POST['questions_filter']) &&
1145
                in_array($row['question_id'], $_POST['questions_filter']))
1146
            ) {
1147
                // We do not show comment and pagebreak question types
1148
                if ('pagebreak' !== $row['type']) {
1149
                    $content .= ' <th';
1150
                    if ($row['number_of_options'] > 0 && 'percentage' !== $row['type']) {
1151
                        $content .= ' colspan="'.$row['number_of_options'].'"';
1152
                    }
1153
                    $content .= '>';
1154
                    $content .= '<label>';
1155
                    if ($addFilters) {
1156
                        $content .= '<input
1157
                                type="checkbox"
1158
                                name="questions_filter[]" value="'.$row['question_id'].'" checked="checked"/>';
1159
                    }
1160
                    $content .= $row['survey_question'];
1161
                    $content .= '</label>';
1162
                    $content .= '</th>';
1163
                }
1164
                // No column at all if it's not a question
1165
            }
1166
            $questions[$row['question_id']] = $row;
1167
        }
1168
        $content .= '	</tr>';
1169
1170
        // Getting all the questions and options
1171
        $content .= '	<tr>';
1172
        $content .= '		<th>&nbsp;</th>'; // the user column
1173
1174
        if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1175
            isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter'])
1176
        ) {
1177
            if ($addExtraFields) {
1178
                // show the fields names for user fields
1179
                foreach ($extra_user_fields as &$field) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $extra_user_fields does not seem to be defined for all execution paths leading up to this point.
Loading history...
1180
                    $content .= '<th>'.$field[3].'</th>';
1181
                }
1182
            }
1183
        }
1184
1185
        // cells with option (none for open question)
1186
        $sql = "SELECT
1187
                    sq.iid question_id,
1188
                    sq.survey_id,
1189
                    sq.survey_question,
1190
                    sq.display,
1191
                    sq.sort,
1192
                    sq.type,
1193
                    sqo.iid question_option_id,
1194
                    sqo.option_text,
1195
                    sqo.sort as option_sort
1196
				FROM $table_survey_question sq
1197
				LEFT JOIN $table_survey_question_option sqo
1198
				ON sq.iid = sqo.question_id
1199
				WHERE
1200
				    survey_question NOT LIKE '%{{%' AND
1201
				    sq.survey_id = $surveyId
1202
				ORDER BY sq.sort ASC, sqo.sort ASC";
1203
        $result = Database::query($sql);
1204
1205
        $display_percentage_header = 1;
1206
        $possible_answers = [];
1207
        // in order to display only once the cell option (and not 100 times)
1208
        while ($row = Database::fetch_array($result)) {
1209
            // We show the options if
1210
            // 1. there is no question filter and the export button has not been clicked
1211
            // 2. there is a question filter but the question is selected for display
1212
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1213
                (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']))
1214
            ) {
1215
                // we do not show comment and pagebreak question types
1216
                if ('open' == $row['type'] || 'comment' == $row['type']) {
1217
                    $content .= '<th>&nbsp;-&nbsp;</th>';
1218
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1219
                    $display_percentage_header = 1;
1220
                } elseif ('percentage' == $row['type'] && $display_percentage_header) {
1221
                    $content .= '<th>&nbsp;%&nbsp;</th>';
1222
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1223
                    $display_percentage_header = 0;
1224
                } elseif ('percentage' == $row['type']) {
1225
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1226
                } elseif ('pagebreak' != $row['type'] && 'percentage' != $row['type']) {
1227
                    $content .= '<th>';
1228
                    $content .= $row['option_text'];
1229
                    $content .= '</th>';
1230
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1231
                    $display_percentage_header = 1;
1232
                }
1233
            }
1234
        }
1235
1236
        $content .= '	</tr>';
1237
1238
        $userCondition = '';
1239
        if (!empty($userId)) {
1240
            $userId = (int) $userId;
1241
            $userCondition = " AND user = $userId ";
1242
        }
1243
1244
        // Getting all the answers of the users
1245
        $old_user = '';
1246
        $answers_of_user = [];
1247
        $sql = "SELECT * FROM $table_survey_answer
1248
                WHERE
1249
                    survey_id = $surveyId
1250
                    $userCondition
1251
                    $sessionCondition
1252
                    $lpItemCondition
1253
                ORDER BY iid, user ASC";
1254
        $result = Database::query($sql);
1255
        $i = 1;
1256
        while ($row = Database::fetch_array($result)) {
1257
            if ($old_user != $row['user'] && '' != $old_user) {
1258
                $userParam = $old_user;
1259
                if (0 != $survey->getAnonymous()) {
1260
                    $userParam = $i;
1261
                    $i++;
1262
                }
1263
                $content .= self::display_complete_report_row(
1264
                    $survey,
1265
                    $possible_answers,
1266
                    $answers_of_user,
1267
                    $userParam,
1268
                    $questions,
1269
                    $display_extra_user_fields
1270
                );
1271
                $answers_of_user = [];
1272
            }
1273
            if (isset($questions[$row['question_id']]) &&
1274
                'open' != $questions[$row['question_id']]['type'] &&
1275
                'comment' != $questions[$row['question_id']]['type']
1276
            ) {
1277
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1278
            } else {
1279
                $answers_of_user[$row['question_id']][0] = $row;
1280
            }
1281
            $old_user = $row['user'];
1282
        }
1283
1284
        $userParam = $old_user;
1285
        if (0 != $survey->getAnonymous()) {
1286
            $userParam = $i;
1287
            $i++;
1288
        }
1289
1290
        $content .= self::display_complete_report_row(
1291
            $survey,
1292
            $possible_answers,
1293
            $answers_of_user,
1294
            $userParam,
1295
            $questions,
1296
            $display_extra_user_fields
1297
        );
1298
1299
        // This is to display the last user
1300
        $content .= '</table>';
1301
        $content .= '</form>';
1302
1303
        return $content;
1304
    }
1305
1306
    /**
1307
     * Return user answers in a row.
1308
     *
1309
     * @return string
1310
     */
1311
    public static function display_complete_report_row(
1312
        CSurvey $survey,
1313
        $possible_options,
1314
        $answers_of_user,
1315
        $user,
1316
        $questions,
1317
        $display_extra_user_fields = false
1318
    ) {
1319
        $user = Security::remove_XSS($user);
1320
        $surveyId = $survey->getIid();
1321
1322
        if (empty($surveyId)) {
1323
            return '';
1324
        }
1325
1326
        $content = '<tr>';
1327
        $url = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
1328
        if (0 == $survey->getAnonymous()) {
1329
            if (0 !== (int) $user) {
1330
                $userInfo = api_get_user_info($user);
1331
                $user_displayed = '-';
1332
                if (!empty($userInfo)) {
1333
                    $user_displayed = $userInfo['complete_name_with_username'];
1334
                }
1335
1336
                $content .= '<th>
1337
                    <a href="'.$url.'&action=userreport&user='.$user.'">'
1338
                        .$user_displayed.'
1339
                    </a>
1340
                    </th>'; // the user column
1341
            } else {
1342
                $content .= '<th>'.$user.'</th>'; // the user column
1343
            }
1344
        } else {
1345
            $content .= '<th>'.get_lang('Anonymous').' '.$user.'</th>';
1346
        }
1347
1348
        if ($display_extra_user_fields) {
1349
            // Show user fields data, if any, for this user
1350
            $user_fields_values = UserManager::get_extra_user_data(
1351
                $user,
1352
                false,
1353
                false,
1354
                false,
1355
                true
1356
            );
1357
            foreach ($user_fields_values as &$value) {
1358
                $content .= '<td align="center">'.$value.'</td>';
1359
            }
1360
        }
1361
1362
        if (is_array($possible_options)) {
1363
            foreach ($possible_options as $question_id => &$possible_option) {
1364
                if ('open' === $questions[$question_id]['type'] || 'comment' === $questions[$question_id]['type']) {
1365
                    $content .= '<td align="center">';
1366
                    if (isset($answers_of_user[$question_id]) && isset($answers_of_user[$question_id]['0'])) {
1367
                        $content .= $answers_of_user[$question_id]['0']['option_id'];
1368
                    }
1369
                    $content .= '</td>';
1370
                } else {
1371
                    foreach ($possible_option as $option_id => $value) {
1372
                        if ('multiplechoiceother' === $questions[$question_id]['type']) {
1373
                            foreach ($answers_of_user[$question_id] as $key => $newValue) {
1374
                                $parts = ch_multiplechoiceother::decodeOptionValue($key);
1375
                                if (isset($parts[0])) {
1376
                                    $data = $answers_of_user[$question_id][$key];
1377
                                    unset($answers_of_user[$question_id][$key]);
1378
                                    $newKey = $parts[0];
1379
                                    $answers_of_user[$question_id][$newKey] = $data;
1380
                                }
1381
                            }
1382
                        }
1383
                        if ('percentage' === $questions[$question_id]['type']) {
1384
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1385
                                $content .= "<td align='center'>";
1386
                                $content .= $answers_of_user[$question_id][$option_id]['value'];
1387
                                $content .= "</td>";
1388
                            }
1389
                        } else {
1390
                            $content .= '<td align="center">';
1391
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1392
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1393
                                    $content .= $answers_of_user[$question_id][$option_id]['value'];
1394
                                } else {
1395
                                    $content .= 'v';
1396
                                }
1397
                            }
1398
                        }
1399
                    }
1400
                }
1401
            }
1402
        }
1403
1404
        $content .= '</tr>';
1405
1406
        return $content;
1407
    }
1408
1409
    /**
1410
     * Quite similar to display_complete_report(), returns an HTML string
1411
     * that can be used in a csv file.
1412
     *
1413
     * @param array $survey_data The basic survey data as initially obtained by SurveyManager::get_survey()
1414
     * @param int   $user_id     The ID of the user asking for the report
1415
     * @param bool  $compact     Whether to present the long (v marks with multiple columns per question) or compact
1416
     *                           (one column per question) answers format
1417
     *
1418
     * @todo consider merging this function with display_complete_report
1419
     *
1420
     * @throws Exception
1421
     *
1422
     * @return string The contents of a csv file
1423
     *
1424
     * @author Patrick Cool <[email protected]>, Ghent University
1425
     *
1426
     * @version February 2007
1427
     */
1428
    public static function export_complete_report($survey_data, $user_id = 0, $compact = false)
1429
    {
1430
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
1431
1432
        if (empty($surveyId)) {
1433
            return false;
1434
        }
1435
1436
        $course = api_get_course_info();
1437
        $course_id = $course['real_id'];
1438
1439
        $sessionCondition = '';
1440
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
1441
            $sessionId = api_get_session_id();
1442
            $sessionCondition = api_get_session_condition($sessionId);
1443
        }
1444
1445
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1446
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1447
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1448
1449
        $translate = false;
1450
        if ('true' === api_get_setting('editor.translate_html')) {
1451
            $translate = true;
1452
        }
1453
1454
        // The first column
1455
        $return = ';';
1456
1457
        // Show extra fields blank space (enough for extra fields on next line)
1458
        $extra_user_fields = UserManager::get_extra_fields(
1459
            0,
1460
            0,
1461
            5,
1462
            'ASC',
1463
            false,
1464
            true
1465
        );
1466
1467
        $num = count($extra_user_fields);
1468
        $return .= str_repeat(';', $num);
1469
1470
        $sql = "SELECT
1471
                    questions.iid,
1472
                    questions.type,
1473
                    questions.survey_question,
1474
                    count(options.iid) as number_of_options
1475
				FROM $table_survey_question questions
1476
                LEFT JOIN $table_survey_question_option options
1477
				ON
1478
				  questions.iid = options.question_id
1479
				WHERE
1480
				    survey_question NOT LIKE '%{{%' AND
1481
				    questions.type <> 'pagebreak' AND
1482
				    questions.survey_id = $surveyId
1483
				GROUP BY questions.iid
1484
				ORDER BY questions.sort ASC";
1485
1486
        $result = Database::query($sql);
1487
        while ($row = Database::fetch_array($result)) {
1488
            if ($translate) {
1489
                $row['survey_question'] = api_get_filtered_multilingual_HTML_string($row['survey_question'], $course['language']);
1490
            }
1491
            // We show the questions if
1492
            // 1. there is no question filter and the export button has not been clicked
1493
            // 2. there is a quesiton filter but the question is selected for display
1494
            if (!(isset($_POST['submit_question_filter'])) ||
1495
                (isset($_POST['submit_question_filter']) &&
1496
                    is_array($_POST['questions_filter']) &&
1497
                    in_array($row['iid'], $_POST['questions_filter']))
1498
            ) {
1499
                if (0 == $row['number_of_options'] || $compact) {
1500
                    $return .= str_replace(
1501
                        "\r\n",
1502
                        '  ',
1503
                        api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1504
                    )
1505
                    .';';
1506
                } else {
1507
                    for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1508
                        $return .= str_replace(
1509
                            "\r\n",
1510
                            '  ',
1511
                            api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1512
                        )
1513
                        .';';
1514
                    }
1515
                }
1516
            }
1517
        }
1518
1519
        $return .= "\n";
1520
        // Getting all the questions and options
1521
        $return .= ';';
1522
        // Show the fields names for user fields
1523
        if (!empty($extra_user_fields)) {
1524
            foreach ($extra_user_fields as &$field) {
1525
                if ($translate) {
1526
                    $field[3] = api_get_filtered_multilingual_HTML_string($field[3], $course['language']);
1527
                }
1528
                $return .= '"'
1529
                    .str_replace(
1530
                        "\r\n",
1531
                        '  ',
1532
                        api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES)
1533
                    )
1534
                    .'";';
1535
            }
1536
        }
1537
1538
        $sql = "SELECT DISTINCT
1539
		            survey_question.iid question_id,
1540
		            survey_question.survey_id,
1541
		            survey_question.survey_question,
1542
		            survey_question.display,
1543
		            survey_question.sort,
1544
		            survey_question.type,
1545
                    survey_question_option.iid question_option_id,
1546
                    survey_question_option.option_text,
1547
                    survey_question_option.sort as option_sort
1548
				FROM $table_survey_question survey_question
1549
				LEFT JOIN $table_survey_question_option survey_question_option
1550
				ON
1551
				    survey_question.iid = survey_question_option.question_id
1552
				WHERE
1553
				    survey_question NOT LIKE '%{{%' AND
1554
				    survey_question.type <> 'pagebreak' AND
1555
				    survey_question.survey_id = $surveyId
1556
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1557
        $result = Database::query($sql);
1558
        $possible_answers = [];
1559
        $possible_answers_type = [];
1560
        while ($row = Database::fetch_array($result)) {
1561
            // We show the options if
1562
            // 1. there is no question filter and the export button has not been clicked
1563
            // 2. there is a question filter but the question is selected for display
1564
            if ($translate) {
1565
                $row['option_text'] = api_get_filtered_multilingual_HTML_string($row['option_text'], $course['language']);
1566
            }
1567
            if (!(isset($_POST['submit_question_filter'])) || (
1568
                is_array($_POST['questions_filter']) &&
1569
                in_array($row['question_id'], $_POST['questions_filter'])
1570
            )
1571
            ) {
1572
                $row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']);
1573
                if (!$compact) {
1574
                    $return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';';
1575
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1576
                } else {
1577
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['option_text'];
1578
                }
1579
                $possible_answers_type[$row['question_id']] = $row['type'];
1580
            }
1581
        }
1582
1583
        $return .= "\n";
1584
1585
        // Getting all the answers of the users
1586
        $old_user = '';
1587
        $answers_of_user = [];
1588
        $sql = "SELECT * FROM $table_survey_answer
1589
		        WHERE
1590
		          survey_id = $surveyId
1591
		          $sessionCondition
1592
		          ";
1593
        if (0 != $user_id) {
1594
            $user_id = (int) $user_id;
1595
            $sql .= " AND user = $user_id ";
1596
        }
1597
        $sql .= ' ORDER BY user ASC ';
1598
1599
        $questionIdList = array_keys($possible_answers_type);
1600
        $open_question_iterator = 1;
1601
        $result = Database::query($sql);
1602
        while ($row = Database::fetch_assoc($result)) {
1603
            if (!in_array($row['question_id'], $questionIdList)) {
1604
                continue;
1605
            }
1606
            if ($old_user != $row['user'] && '' != $old_user) {
1607
                $return .= self::export_complete_report_row(
1608
                    $survey_data,
1609
                    $possible_answers,
1610
                    $answers_of_user,
1611
                    $old_user,
1612
                    true,
1613
                    $compact
1614
                );
1615
                $answers_of_user = [];
1616
            }
1617
1618
            if ('open' === $possible_answers_type[$row['question_id']] ||
1619
                'comment' === $possible_answers_type[$row['question_id']]
1620
            ) {
1621
                $temp_id = 'open'.$open_question_iterator;
1622
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1623
                $open_question_iterator++;
1624
            } else {
1625
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1626
            }
1627
            $old_user = $row['user'];
1628
        }
1629
1630
        // This is to display the last user
1631
        $return .= self::export_complete_report_row(
1632
            $survey_data,
1633
            $possible_answers,
1634
            $answers_of_user,
1635
            $old_user,
1636
            true,
1637
            $compact
1638
        );
1639
1640
        return $return;
1641
    }
1642
1643
    /**
1644
     * Add a line to the csv file.
1645
     *
1646
     * @param array $survey_data               Basic survey data (we're mostly interested in the 'anonymous' index)
1647
     * @param array $possible_options          Possible answers
1648
     * @param array $answers_of_user           User's answers
1649
     * @param mixed $user                      User ID or user details as string - Used as a string in the result
1650
     *                                         string
1651
     * @param bool  $display_extra_user_fields Whether to display user fields or not
1652
     * @param bool  $compact                   Whether to show answers as different column values (true) or one column
1653
     *                                         per option (false, default)
1654
     *
1655
     * @return string One line of the csv file
1656
     *
1657
     * @author Patrick Cool <[email protected]>, Ghent University
1658
     *
1659
     * @version February 2007
1660
     */
1661
    public static function export_complete_report_row(
1662
        CSurvey $survey,
1663
        $possible_options,
1664
        $answers_of_user,
1665
        $user,
1666
        $display_extra_user_fields = false,
1667
        $compact = false
1668
    ) {
1669
        $return = '';
1670
        if (0 == $survey->getAnonymous()) {
1671
            if (0 !== intval($user)) {
1672
                $userInfo = api_get_user_info($user);
1673
                if (!empty($userInfo)) {
1674
                    $user_displayed = $userInfo['complete_name_with_username'];
1675
                } else {
1676
                    $user_displayed = '-';
1677
                }
1678
                $return .= $user_displayed.';';
1679
            } else {
1680
                $return .= $user.';';
1681
            }
1682
        } else {
1683
            $return .= '-;'; // The user column
1684
        }
1685
1686
        if ($display_extra_user_fields) {
1687
            // Show user fields data, if any, for this user
1688
            $user_fields_values = UserManager::get_extra_user_data(
1689
                $user,
1690
                false,
1691
                false,
1692
                false,
1693
                true
1694
            );
1695
            foreach ($user_fields_values as &$value) {
1696
                $return .= '"'.str_replace('"', '""', api_html_entity_decode(strip_tags($value), ENT_QUOTES)).'";';
1697
            }
1698
        }
1699
1700
        if (is_array($possible_options)) {
1701
            foreach ($possible_options as $question_id => $possible_option) {
1702
                if (is_array($possible_option) && count($possible_option) > 0) {
1703
                    foreach ($possible_option as $option_id => &$value) {
1704
                        // For each option of this question, look if it matches the user's answer
1705
                        $my_answer_of_user = !isset($answers_of_user[$question_id]) || isset($answers_of_user[$question_id]) && null == $answers_of_user[$question_id] ? [] : $answers_of_user[$question_id];
1706
                        $key = array_keys($my_answer_of_user);
1707
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
1708
                            // If this is an open type question (type starts by 'open'), take whatever answer is given
1709
                            $return .= '"'.
1710
                                str_replace(
1711
                                    '"',
1712
                                    '""',
1713
                                    api_html_entity_decode(
1714
                                        strip_tags(
1715
                                            $answers_of_user[$question_id][$key[0]]['option_id']
1716
                                        ),
1717
                                        ENT_QUOTES
1718
                                    )
1719
                                ).
1720
                                '";';
1721
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1722
                            //$return .= 'v';
1723
                            if ($compact) {
1724
                                // If we asked for a compact view, show only one column for the question
1725
                                // and fill it with the text of the selected option (i.e. "Yes") instead of an ID
1726
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1727
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1728
                                } else {
1729
                                    $return .= '"'.
1730
                                        str_replace(
1731
                                            '"',
1732
                                            '""',
1733
                                            api_html_entity_decode(
1734
                                                strip_tags(
1735
                                                    $possible_option[$option_id]
1736
                                                ),
1737
                                                ENT_QUOTES
1738
                                            )
1739
                                        ).
1740
                                        '";';
1741
                                }
1742
                            } else {
1743
                                // If we don't want a compact view, show one column per possible option and mark a 'v'
1744
                                // or the defined value in the corresponding column if the user selected it
1745
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1746
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1747
                                } else {
1748
                                    $return .= 'v;';
1749
                                }
1750
                            }
1751
                        } else {
1752
                            if (!$compact) {
1753
                                $return .= ';';
1754
                            }
1755
                        }
1756
                    }
1757
                }
1758
            }
1759
        }
1760
        $return .= "\n";
1761
1762
        return $return;
1763
    }
1764
1765
    public static function export_complete_report_xls(CSurvey $survey, $filename, $user_id = 0, $returnFile = false)
1766
    {
1767
        $course_id = api_get_course_int_id();
1768
        $user_id = (int) $user_id;
1769
        $surveyId = $survey->getIid();
1770
1771
        if (empty($course_id) || empty($surveyId)) {
1772
            return false;
1773
        }
1774
1775
        // Show extra fields blank space (enough for extra fields on next line)
1776
        // Show user fields section with a big th colspan that spans over all fields
1777
        $extra_user_fields = UserManager::get_extra_fields(
1778
            0,
1779
            0,
1780
            5,
1781
            'ASC',
1782
            false,
1783
            true
1784
        );
1785
        $list = [];
1786
        $num = count($extra_user_fields);
1787
        for ($i = 0; $i < $num; $i++) {
1788
            $list[0][] = '';
1789
        }
1790
1791
        $display_extra_user_fields = true;
1792
1793
        // Database table definitions
1794
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1795
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1796
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1797
1798
        // First line (questions)
1799
        $sql = "SELECT
1800
                    questions.question_id,
1801
                    questions.type,
1802
                    questions.survey_question,
1803
                    count(options.iid) as number_of_options
1804
				FROM $table_survey_question questions
1805
				LEFT JOIN $table_survey_question_option options
1806
                ON
1807
                  questions.iid = options.question_id
1808
				WHERE
1809
				    survey_question NOT LIKE '%{{%' AND
1810
				    questions.type <> 'pagebreak' AND
1811
				    questions.survey_id = $surveyId
1812
				GROUP BY questions.question_id
1813
				ORDER BY questions.sort ASC";
1814
        $result = Database::query($sql);
1815
        $line = 1;
1816
        $column = 1;
1817
        while ($row = Database::fetch_array($result)) {
1818
            // We show the questions if
1819
            // 1. there is no question filter and the export button has not been clicked
1820
            // 2. there is a quesiton filter but the question is selected for display
1821
            if (!(isset($_POST['submit_question_filter'])) ||
1822
                (isset($_POST['submit_question_filter']) && is_array($_POST['questions_filter']) &&
1823
                in_array($row['question_id'], $_POST['questions_filter']))
1824
            ) {
1825
                // We do not show comment and pagebreak question types
1826
                if ('pagebreak' !== $row['type']) {
1827
                    if (0 == $row['number_of_options'] && ('open' === $row['type'] || 'comment' === $row['type'])) {
1828
                        $list[$line][$column] = api_html_entity_decode(
1829
                            strip_tags($row['survey_question']),
1830
                            ENT_QUOTES
1831
                        );
1832
                        $column++;
1833
                    } else {
1834
                        for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1835
                            $list[$line][$column] = api_html_entity_decode(
1836
                                strip_tags($row['survey_question']),
1837
                                ENT_QUOTES
1838
                            );
1839
                            $column++;
1840
                        }
1841
                    }
1842
                }
1843
            }
1844
        }
1845
1846
        $line++;
1847
        $column = 1;
1848
        // Show extra field values
1849
        if ($display_extra_user_fields) {
1850
            // Show the fields names for user fields
1851
            foreach ($extra_user_fields as &$field) {
1852
                $list[$line][$column] = api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES);
1853
                $column++;
1854
            }
1855
        }
1856
1857
        // Getting all the questions and options (second line)
1858
        $sql = "SELECT
1859
                    survey_question.iid question_id,
1860
                    survey_question.survey_id,
1861
                    survey_question.survey_question,
1862
                    survey_question.display,
1863
                    survey_question.sort,
1864
                    survey_question.type,
1865
                    survey_question_option.iid question_option_id,
1866
                    survey_question_option.option_text,
1867
                    survey_question_option.sort as option_sort
1868
				FROM $table_survey_question survey_question
1869
				LEFT JOIN $table_survey_question_option survey_question_option
1870
				ON
1871
				    survey_question.iid = survey_question_option.question_id
1872
				WHERE
1873
				    survey_question NOT LIKE '%{{%' AND
1874
				    survey_question.type <> 'pagebreak' AND
1875
				    survey_question.survey_id = $surveyId
1876
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1877
        $result = Database::query($sql);
1878
        $possible_answers = [];
1879
        $possible_answers_type = [];
1880
        while ($row = Database::fetch_array($result)) {
1881
            // We show the options if
1882
            // 1. there is no question filter and the export button has not been clicked
1883
            // 2. there is a quesiton filter but the question is selected for display
1884
            if (!isset($_POST['submit_question_filter']) ||
1885
                (isset($_POST['questions_filter']) && is_array($_POST['questions_filter']) &&
1886
                in_array($row['question_id'], $_POST['questions_filter']))
1887
            ) {
1888
                // We do not show comment and pagebreak question types
1889
                if ('pagebreak' !== $row['type']) {
1890
                    $list[$line][$column] = api_html_entity_decode(
1891
                        strip_tags($row['option_text']),
1892
                        ENT_QUOTES
1893
                    );
1894
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1895
                    $possible_answers_type[$row['question_id']] = $row['type'];
1896
                    $column++;
1897
                }
1898
            }
1899
        }
1900
1901
        // Getting all the answers of the users
1902
        $line++;
1903
        $column = 0;
1904
        $old_user = '';
1905
        $answers_of_user = [];
1906
        $sql = "SELECT * FROM $table_survey_answer
1907
                WHERE c_id = $course_id AND survey_id = $surveyId";
1908
        if (0 != $user_id) {
1909
            $sql .= " AND user='".$user_id."' ";
1910
        }
1911
        $sql .= ' ORDER BY user ASC';
1912
1913
        $open_question_iterator = 1;
1914
        $result = Database::query($sql);
1915
        while ($row = Database::fetch_array($result)) {
1916
            if ($old_user != $row['user'] && '' != $old_user) {
1917
                $return = self::export_complete_report_row_xls(
1918
                    $survey,
1919
                    $possible_answers,
1920
                    $answers_of_user,
1921
                    $old_user,
1922
                    true
1923
                );
1924
                foreach ($return as $elem) {
1925
                    $list[$line][$column] = $elem;
1926
                    $column++;
1927
                }
1928
                $answers_of_user = [];
1929
                $line++;
1930
                $column = 0;
1931
            }
1932
            if ('open' === $possible_answers_type[$row['question_id']] || 'comment' === $possible_answers_type[$row['question_id']]) {
1933
                $temp_id = 'open'.$open_question_iterator;
1934
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1935
                $open_question_iterator++;
1936
            } else {
1937
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1938
            }
1939
            $old_user = $row['user'];
1940
        }
1941
1942
        $return = self::export_complete_report_row_xls(
1943
            $survey,
1944
            $possible_answers,
1945
            $answers_of_user,
1946
            $old_user,
1947
            true
1948
        );
1949
1950
        // this is to display the last user
1951
        if (!empty($return)) {
1952
            foreach ($return as $elem) {
1953
                $list[$line][$column] = $elem;
1954
                $column++;
1955
            }
1956
        }
1957
1958
        Export::arrayToXls($list, $filename);
1959
1960
        return null;
1961
    }
1962
1963
    /**
1964
     * Add a line to the csv file.
1965
     *
1966
     * @param array Possible answers
1967
     * @param array User's answers
0 ignored issues
show
Documentation Bug introduced by
The doc comment User's at position 0 could not be parsed: Unknown type name 'User's' at position 0 in User's.
Loading history...
1968
     * @param mixed User ID or user details as string - Used as a string in the result string
1969
     * @param bool Whether to display user fields or not
1970
     *
1971
     * @return array
1972
     */
1973
    public static function export_complete_report_row_xls(
1974
        CSurvey $survey,
1975
        $possible_options,
1976
        $answers_of_user,
1977
        $user,
1978
        $display_extra_user_fields = false
1979
    ) {
1980
        $return = [];
1981
        if (0 == $survey->getAnonymous()) {
1982
            if (0 !== (int) $user) {
1983
                $userInfo = api_get_user_info($user);
1984
                if ($userInfo) {
1985
                    $user_displayed = $userInfo['complete_name_with_username'];
1986
                } else {
1987
                    $user_displayed = '-';
1988
                }
1989
                $return[] = $user_displayed;
1990
            } else {
1991
                $return[] = $user;
1992
            }
1993
        } else {
1994
            $return[] = '-'; // The user column
1995
        }
1996
1997
        if ($display_extra_user_fields) {
1998
            //show user fields data, if any, for this user
1999
            $user_fields_values = UserManager::get_extra_user_data(
2000
                $user,
2001
                false,
2002
                false,
2003
                false,
2004
                true
2005
            );
2006
            foreach ($user_fields_values as $value) {
2007
                $return[] = api_html_entity_decode(strip_tags($value), ENT_QUOTES);
2008
            }
2009
        }
2010
2011
        if (is_array($possible_options)) {
2012
            foreach ($possible_options as $question_id => &$possible_option) {
2013
                if (is_array($possible_option) && count($possible_option) > 0) {
2014
                    foreach ($possible_option as $option_id => &$value) {
2015
                        $my_answers_of_user = $answers_of_user[$question_id] ?? [];
2016
                        $key = array_keys($my_answers_of_user);
2017
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
2018
                            $return[] = api_html_entity_decode(
2019
                                strip_tags($answers_of_user[$question_id][$key[0]]['option_id']),
2020
                                ENT_QUOTES
2021
                            );
2022
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
2023
                            if (0 != $answers_of_user[$question_id][$option_id]['value']) {
2024
                                $return[] = $answers_of_user[$question_id][$option_id]['value'];
2025
                            } else {
2026
                                $return[] = 'v';
2027
                            }
2028
                        } else {
2029
                            $return[] = '';
2030
                        }
2031
                    }
2032
                }
2033
            }
2034
        }
2035
2036
        return $return;
2037
    }
2038
2039
    /**
2040
     * This function displays the comparative report which
2041
     * allows you to compare two questions
2042
     * A comparative report creates a table where one question
2043
     * is on the x axis and a second question is on the y axis.
2044
     * In the intersection is the number of people who have
2045
     * answered positive on both options.
2046
     *
2047
     * @return string HTML code
2048
     *
2049
     * @author Patrick Cool <[email protected]>, Ghent University
2050
     *
2051
     * @version February 2007
2052
     */
2053
    public static function display_comparative_report()
2054
    {
2055
        // Allowed question types for comparative report
2056
        $allowed_question_types = [
2057
            'yesno',
2058
            'multiplechoice',
2059
            'multipleresponse',
2060
            'dropdown',
2061
            'percentage',
2062
            'score',
2063
        ];
2064
2065
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
2066
2067
        // Getting all the questions
2068
        $questions = SurveyManager::get_questions($surveyId);
2069
2070
        // Actions bar
2071
        $actions = '<a href="'.api_get_path(
2072
                WEB_CODE_PATH
2073
            ).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq()
2074
            .'">'
2075
            .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'))
2076
            .'</a>';
2077
        echo Display::toolbarAction('survey', [$actions]);
2078
2079
        // Displaying an information message that only the questions with predefined answers can be used in a comparative report
2080
        echo Display::return_message(get_lang('Only questions with predefined answers can be used'), 'normal', false);
2081
2082
        $xAxis = isset($_GET['xaxis']) ? Security::remove_XSS($_GET['xaxis']) : '';
2083
        $yAxis = isset($_GET['yaxis']) ? Security::remove_XSS($_GET['yaxis']) : '';
2084
2085
        $url = api_get_self().'?'.api_get_cidreq().'&action='.Security::remove_XSS($_GET['action'])
2086
            .'&survey_id='.$surveyId.'&xaxis='.$xAxis.'&y='.$yAxis;
2087
2088
        $form = new FormValidator('compare', 'get', $url);
2089
        $form->addHidden('action', Security::remove_XSS($_GET['action']));
2090
        $form->addHidden('survey_id', $surveyId);
2091
        $optionsX = ['----'];
2092
        $optionsY = ['----'];
2093
        $defaults = [];
2094
        foreach ($questions as $key => &$question) {
2095
            // Ignored tagged questions
2096
            if ($question) {
2097
                if (false !== strpos($question['question'], '{{')) {
2098
                    $question = null;
2099
                    continue;
2100
                }
2101
            }
2102
            if (is_array($allowed_question_types)) {
2103
                if (in_array($question['type'], $allowed_question_types)) {
2104
                    if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) {
2105
                        $defaults['xaxis'] = $question['question_id'];
2106
                    }
2107
2108
                    if (isset($_GET['yaxis']) && $_GET['yaxis'] == $question['question_id']) {
2109
                        $defaults['yaxis'] = $question['question_id'];
2110
                    }
2111
2112
                    $optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2113
                    $optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2114
                }
2115
            }
2116
        }
2117
2118
        $form->addSelect('xaxis', get_lang('Select the question on the X axis'), $optionsX);
2119
        $form->addSelect('yaxis', get_lang('Select the question on the Y axis'), $optionsY);
2120
2121
        $form->addButtonSearch(get_lang('Compare questions'));
2122
        $form->setDefaults($defaults);
2123
        $form->display();
2124
2125
        // Getting all the information of the x axis
2126
        if (is_numeric($xAxis)) {
2127
            $question_x = SurveyManager::get_question($xAxis);
2128
        }
2129
2130
        // Getting all the information of the y axis
2131
        if (is_numeric($yAxis)) {
2132
            $question_y = SurveyManager::get_question($yAxis);
2133
        }
2134
2135
        if (is_numeric($xAxis) && is_numeric($yAxis) && $question_x && $question_y) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_x does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $question_y does not seem to be defined for all execution paths leading up to this point.
Loading history...
2136
            // Getting the answers of the two questions
2137
            $answers_x = self::get_answers_of_question_by_user($surveyId, $xAxis);
2138
            $answers_y = self::get_answers_of_question_by_user($surveyId, $yAxis);
2139
2140
            // Displaying the table
2141
            $tableHtml = '<table border="1" class="table table-hover table-striped data_table">';
2142
            $xOptions = [];
2143
            // The header
2144
            $tableHtml .= '<tr>';
2145
            for ($ii = 0; $ii <= count($question_x['answers']); $ii++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2146
                if (0 == $ii) {
2147
                    $tableHtml .= '<th>&nbsp;</th>';
2148
                } else {
2149
                    if ('score' == $question_x['type']) {
2150
                        for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2151
                            $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'<br />'.$x.'</th>';
2152
                        }
2153
                        $x = '';
2154
                    } else {
2155
                        $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'</th>';
2156
                    }
2157
                    $optionText = strip_tags($question_x['answers'][$ii - 1]);
2158
                    $optionText = html_entity_decode($optionText);
2159
                    array_push($xOptions, trim($optionText));
2160
                }
2161
            }
2162
            $tableHtml .= '</tr>';
2163
            $chartData = [];
2164
            // The main part
2165
            for ($ij = 0; $ij < count($question_y['answers']); $ij++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2166
                $currentYQuestion = strip_tags($question_y['answers'][$ij]);
2167
                $currentYQuestion = html_entity_decode($currentYQuestion);
2168
                // The Y axis is a scoring question type so we have more rows than the options (actually options * maximum score)
2169
                if ('score' == $question_y['type']) {
2170
                    for ($y = 1; $y <= $question_y['maximum_score']; $y++) {
2171
                        $tableHtml .= '<tr>';
2172
                        for ($ii = 0; $ii <= count($question_x['answers']); $ii++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2173
                            if ('score' == $question_x['type']) {
2174
                                for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2175
                                    if (0 == $ii) {
2176
                                        $tableHtml .= '<th>'.$question_y['answers'][($ij)].' '.$y.'</th>';
2177
                                        break;
2178
                                    } else {
2179
                                        $tableHtml .= '<td align="center">';
2180
                                        $votes = self::comparative_check(
2181
                                            $answers_x,
2182
                                            $answers_y,
2183
                                            $question_x['answersid'][($ii - 1)],
2184
                                            $question_y['answersid'][($ij)],
2185
                                            $x,
2186
                                            $y
2187
                                        );
2188
                                        $tableHtml .= $votes;
2189
                                        array_push(
2190
                                            $chartData,
2191
                                            [
2192
                                                'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2193
                                                'option' => $x,
2194
                                                'votes' => $votes,
2195
                                            ]
2196
                                        );
2197
                                        $tableHtml .= '</td>';
2198
                                    }
2199
                                }
2200
                            } else {
2201
                                if (0 == $ii) {
2202
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].' '.$y.'</th>';
2203
                                } else {
2204
                                    $tableHtml .= '<td align="center">';
2205
                                    $votes = self::comparative_check(
2206
                                        $answers_x,
2207
                                        $answers_y,
2208
                                        $question_x['answersid'][($ii - 1)],
2209
                                        $question_y['answersid'][($ij)],
2210
                                        0,
2211
                                        $y
2212
                                    );
2213
                                    $tableHtml .= $votes;
2214
                                    array_push(
2215
                                        $chartData,
2216
                                        [
2217
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2218
                                            'option' => $y,
2219
                                            'votes' => $votes,
2220
                                        ]
2221
                                    );
2222
                                    $tableHtml .= '</td>';
2223
                                }
2224
                            }
2225
                        }
2226
                        $tableHtml .= '</tr>';
2227
                    }
2228
                } else {
2229
                    // The Y axis is NOT a score question type so the number of rows = the number of options
2230
                    $tableHtml .= '<tr>';
2231
                    for ($ii = 0; $ii <= count($question_x['answers']); $ii++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2232
                        if ('score' == $question_x['type']) {
2233
                            for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2234
                                if (0 == $ii) {
2235
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].'</th>';
2236
                                    break;
2237
                                } else {
2238
                                    $tableHtml .= '<td align="center">';
2239
                                    $votes = self::comparative_check(
2240
                                        $answers_x,
2241
                                        $answers_y,
2242
                                        $question_x['answersid'][($ii - 1)],
2243
                                        $question_y['answersid'][($ij)],
2244
                                        $x,
2245
                                        0
2246
                                    );
2247
                                    $tableHtml .= $votes;
2248
                                    array_push(
2249
                                        $chartData,
2250
                                        [
2251
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2252
                                            'option' => $x,
2253
                                            'votes' => $votes,
2254
                                        ]
2255
                                    );
2256
                                    $tableHtml .= '</td>';
2257
                                }
2258
                            }
2259
                        } else {
2260
                            if (0 == $ii) {
2261
                                $tableHtml .= '<th>'.$question_y['answers'][($ij)].'</th>';
2262
                            } else {
2263
                                $tableHtml .= '<td align="center">';
2264
                                $votes = self::comparative_check(
2265
                                    $answers_x,
2266
                                    $answers_y,
2267
                                    $question_x['answersid'][($ii - 1)],
2268
                                    $question_y['answersid'][($ij)]
2269
                                );
2270
                                $tableHtml .= $votes;
2271
                                array_push(
2272
                                    $chartData,
2273
                                    [
2274
                                        'serie' => $xOptions[$ii - 1],
2275
                                        'option' => $currentYQuestion,
2276
                                        'votes' => $votes,
2277
                                    ]
2278
                                );
2279
                                $tableHtml .= '</td>';
2280
                            }
2281
                        }
2282
                    }
2283
                    $tableHtml .= '</tr>';
2284
                }
2285
            }
2286
            $tableHtml .= '</table>';
2287
            echo '<div id="chartContainer" class="col-md-12">';
2288
            echo self::drawChart($chartData, true);
2289
            echo '</div>';
2290
            echo $tableHtml;
2291
        }
2292
    }
2293
2294
    /**
2295
     * Get all the answers of a question grouped by user.
2296
     *
2297
     * @param int $survey_id   Survey ID
2298
     * @param int $question_id Question ID
2299
     *
2300
     * @return array Array containing all answers of all users, grouped by user
2301
     *
2302
     * @author Patrick Cool <[email protected]>, Ghent University
2303
     *
2304
     * @version February 2007 - Updated March 2008
2305
     */
2306
    public static function get_answers_of_question_by_user($survey_id, $question_id, $lpItemId = 0)
2307
    {
2308
        $course_id = api_get_course_int_id();
2309
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
2310
2311
        $sessionCondition = '';
2312
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
2313
            $sessionId = api_get_session_id();
2314
            $sessionCondition = api_get_session_condition($sessionId);
2315
        }
2316
        $lpItemCondition = '';
2317
        if (!empty($lpItemId)) {
2318
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
2319
        }
2320
2321
        $sql = "SELECT * FROM $table_survey_answer
2322
                WHERE
2323
                  survey_id='".intval($survey_id)."' AND
2324
                  question_id='".intval($question_id)."'
2325
                  $sessionCondition
2326
                  $lpItemCondition
2327
                ORDER BY USER ASC";
2328
        $result = Database::query($sql);
2329
        $return = [];
2330
        while ($row = Database::fetch_array($result)) {
2331
            if (0 == $row['value']) {
2332
                $return[$row['user']][] = $row['option_id'];
2333
            } else {
2334
                $return[$row['user']][] = $row['option_id'].'*'.$row['value'];
2335
            }
2336
        }
2337
2338
        return $return;
2339
    }
2340
2341
    /**
2342
     * Count the number of users who answer positively on both options.
2343
     *
2344
     * @param array All answers of the x axis
2345
     * @param array All answers of the y axis
2346
     * @param int x axis value (= the option_id of the first question)
2347
     * @param int y axis value (= the option_id of the second question)
2348
     *
2349
     * @return int Number of users who have answered positively to both options
2350
     *
2351
     * @author Patrick Cool <[email protected]>, Ghent University
2352
     *
2353
     * @version February 2007
2354
     */
2355
    public static function comparative_check(
2356
        $answers_x,
2357
        $answers_y,
2358
        $option_x,
2359
        $option_y,
2360
        $value_x = 0,
2361
        $value_y = 0
2362
    ) {
2363
        if (0 == $value_x) {
2364
            $check_x = $option_x;
2365
        } else {
2366
            $check_x = $option_x.'*'.$value_x;
2367
        }
2368
        if (0 == $value_y) {
2369
            $check_y = $option_y;
2370
        } else {
2371
            $check_y = $option_y.'*'.$value_y;
2372
        }
2373
2374
        $counter = 0;
2375
        if (is_array($answers_x)) {
2376
            foreach ($answers_x as $user => &$answers) {
2377
                // Check if the user has given $option_x as answer
2378
                if (in_array($check_x, $answers)) {
2379
                    // Check if the user has given $option_y as an answer
2380
                    if (!is_null($answers_y[$user]) &&
2381
                        in_array($check_y, $answers_y[$user])
2382
                    ) {
2383
                        $counter++;
2384
                    }
2385
                }
2386
            }
2387
        }
2388
2389
        return $counter;
2390
    }
2391
2392
    public static function saveInviteMail(CSurvey $survey, $content, $subject, $remind)
2393
    {
2394
        // Database table definition
2395
        if ($remind) {
2396
            $survey->setReminderMail($content);
2397
        } else {
2398
            $survey->setInviteMail($content);
2399
        }
2400
2401
        $survey->setMailSubject($subject);
2402
        $em = Database::getManager();
2403
        $em->persist($survey);
2404
        $em->flush();
2405
    }
2406
2407
    /**
2408
     * This function saves all the invitations of course users
2409
     * and additional users in the database
2410
     * and sends the invitations by email.
2411
     *
2412
     * @param int    $surveyId
2413
     * @param array  $users_array       Users array can be both a list of course uids AND a list of additional email
2414
     *                                  addresses
2415
     * @param string $invitation_title  title of the mail
2416
     * @param string $invitation_text   text of the mail has to contain a **link** string or
2417
     *                                  this will automatically be added to the end
2418
     * @param int    $reminder
2419
     * @param bool   $sendmail
2420
     * @param int    $remindUnAnswered
2421
     * @param bool   $isAdditionalEmail
2422
     * @param bool   $hideLink
2423
     *
2424
     * @author Patrick Cool <[email protected]>, Ghent University
2425
     * @author Julio Montoya - Adding auto-generated link support
2426
     *
2427
     * @version January 2007
2428
     */
2429
    public static function saveInvitations(
2430
        CSurvey $survey,
2431
        $users_array,
2432
        $invitation_title,
2433
        $invitation_text,
2434
        $reminder = 0,
2435
        $sendmail = false,
2436
        $remindUnAnswered = 0,
2437
        $isAdditionalEmail = false,
2438
        $hideLink = false
2439
    ) {
2440
        $surveyId = $survey->getIid();
2441
2442
        if (!is_array($users_array)) {
2443
            return 0;
2444
        }
2445
        $course = api_get_course_entity();
2446
        $session = api_get_session_entity();
2447
        $survey_invitations = self::get_invitations($surveyId);
2448
        $already_invited = self::get_invited_users($survey);
2449
2450
        // Remind unanswered is a special version of remind all reminder
2451
        $exclude_users = [];
2452
        if (1 == $remindUnAnswered) {
2453
            // Remind only unanswered users
2454
            $reminder = 1;
2455
            $exclude_users = SurveyManager::get_people_who_filled_survey($surveyId);
2456
        }
2457
2458
        $counter = 0; // Nr of invitations "sent" (if sendmail option)
2459
        $course_id = api_get_course_int_id();
2460
        $session_id = api_get_session_id();
2461
2462
        if (false == $isAdditionalEmail) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2463
            $result = AbstractResource::separateUsersGroups($users_array);
2464
            $groupList = $result['groups'];
2465
            $users_array = $result['users'];
2466
2467
            foreach ($groupList as $groupId) {
2468
                $group = api_get_group_entity($groupId);
2469
                $userGroupList = GroupManager::getStudents($groupId, true);
2470
                $userGroupIdList = array_column($userGroupList, 'user_id');
2471
                $users_array = array_merge($users_array, $userGroupIdList);
2472
2473
                /*$params = [
2474
                    'c_id' => $course_id,
2475
                    'session_id' => $session_id,
2476
                    'group_id' => $groupId,
2477
                    'survey_code' => $survey_data['code'],
2478
                ];*/
2479
2480
                $invitationExists = self::invitationExists(
2481
                    $course_id,
2482
                    $session_id,
2483
                    $groupId,
2484
                    $survey->getIid()
2485
                );
2486
                if (empty($invitationExists)) {
2487
                    self::saveInvitation(
2488
                        '',
2489
                        '',
2490
                        api_get_utc_datetime(time(), false, true),
2491
                        $survey,
2492
                        $course,
2493
                        $session,
2494
                        $group
2495
                    );
2496
                }
2497
            }
2498
        }
2499
2500
        $users_array = array_unique($users_array);
2501
        foreach ($users_array as $value) {
2502
            if (empty($value)) {
2503
                continue;
2504
            }
2505
2506
            // Skip user if reminding only unanswered people
2507
            if (in_array($value, $exclude_users)) {
2508
                continue;
2509
            }
2510
2511
            // Get the unique invitation code if we already have it
2512
            if (1 == $reminder && array_key_exists($value, $survey_invitations)) {
2513
                $invitation_code = $survey_invitations[$value]['invitation_code'];
2514
            } else {
2515
                $invitation_code = md5($value.microtime());
2516
            }
2517
            $new_user = false; // User not already invited
2518
            // Store the invitation if user_id not in $already_invited['course_users'] OR
2519
            // email is not in $already_invited['additional_users']
2520
            $addit_users_array = isset($already_invited['additional_users']) && !empty($already_invited['additional_users'])
2521
                    ? explode(';', $already_invited['additional_users'])
2522
                    : [];
2523
            $my_alredy_invited = $already_invited['course_users'] ?? [];
2524
2525
            $userId = 0;
2526
            if (is_string($value) && filter_var($value, FILTER_VALIDATE_EMAIL)) {
2527
                $userInfo = api_get_user_info_from_email($value);
2528
                if ($userInfo && isset($userInfo['id'])) {
2529
                    $userId = $userInfo['id'];
2530
                }
2531
            } elseif (is_numeric($value)) {
2532
                $userId = $value;
2533
            }
2534
2535
            if ($userId && !in_array($userId, $my_alredy_invited)) {
2536
                $new_user = true;
2537
                if (!array_key_exists($userId, $survey_invitations)) {
2538
                    self::saveInvitation(
2539
                        api_get_user_entity($userId),
2540
                        $invitation_code,
2541
                        api_get_utc_datetime(time(), null, true),
2542
                        $survey,
2543
                        $course,
2544
                        $session
2545
                    );
2546
                }
2547
            }
2548
2549
            // Send the email if checkboxed
2550
            if (($new_user || 1 == $reminder) && $sendmail) {
2551
                // Make a change for absolute url
2552
                if (isset($invitation_text)) {
2553
                    $invitation_text = api_html_entity_decode($invitation_text, ENT_QUOTES);
2554
                    $invitation_text = str_replace('src="../../', 'src="'.api_get_path(WEB_PATH), $invitation_text);
2555
                    $invitation_text = trim(stripslashes($invitation_text));
2556
                }
2557
                self::sendInvitationMail(
2558
                    $survey,
2559
                    $value,
2560
                    $course,
2561
                    $invitation_code,
2562
                    $invitation_title,
2563
                    $invitation_text,
2564
                    $hideLink
2565
                );
2566
                $counter++;
2567
            }
2568
        }
2569
2570
        return $counter; // Number of invitations sent
2571
    }
2572
2573
    public static function saveInvitation(
2574
        User $user,
2575
        $invitationCode,
2576
        $reminderDate,
2577
        CSurvey $survey,
2578
        Course $course,
2579
        SessionEntity $session = null,
2580
        CGroup $group = null
2581
    ): ?CSurveyInvitation {
2582
        $invitation = new CSurveyInvitation();
2583
        $invitation
2584
            ->setUser($user)
2585
            ->setInvitationCode($invitationCode)
2586
            ->setReminderDate($reminderDate)
2587
            ->setSurvey($survey)
2588
            ->setCourse($course)
2589
            ->setSession($session)
2590
            ->setGroup($group)
2591
        ;
2592
2593
        $em = Database::getManager();
2594
        $em->persist($invitation);
2595
        $em->flush();
2596
2597
        return $invitation;
2598
    }
2599
2600
    /**
2601
     * @param int $courseId
2602
     * @param int $sessionId
2603
     * @param int $groupId
2604
     * @param int $surveyId
2605
     *
2606
     * @return int
2607
     */
2608
    public static function invitationExists($courseId, $sessionId, $groupId, $surveyId)
2609
    {
2610
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
2611
        $courseId = (int) $courseId;
2612
        $sessionId = (int) $sessionId;
2613
        $groupId = (int) $groupId;
2614
        $surveyId = (int) $surveyId;
2615
2616
        $sql = "SELECT iid FROM $table
2617
                WHERE
2618
                    c_id = $courseId AND
2619
                    session_id = $sessionId AND
2620
                    group_id = $groupId AND
2621
                    survey_id = $surveyId
2622
                ";
2623
        $result = Database::query($sql);
2624
2625
        return Database::num_rows($result);
2626
    }
2627
2628
    /**
2629
     * Send the invitation by mail.
2630
     *
2631
     * @param int invitedUser - the userId (course user) or emailaddress of additional user
2632
     * @param string $invitation_code - the unique invitation code for the URL
2633
     */
2634
    public static function sendInvitationMail(
2635
        CSurvey $survey,
2636
        $invitedUser,
2637
        Course $course,
2638
        $invitation_code,
2639
        $invitation_title,
2640
        $invitation_text,
2641
        $hideLink = false
2642
    ) {
2643
        $_user = api_get_user_info();
2644
        $sessionId = api_get_session_id();
2645
2646
        // Replacing the **link** part with a valid link for the user
2647
        $link = self::generateFillSurveyLink($survey, $invitation_code, $course, $sessionId);
2648
        if ($hideLink) {
2649
            $full_invitation_text = str_replace('**link**', '', $invitation_text);
2650
        } else {
2651
            $text_link = '<a href="'.$link.'">'.get_lang('Click here to answer the survey')."</a><br />\r\n<br />\r\n"
2652
                .get_lang('or copy paste the following url :')." <br /> \r\n <br /> \r\n ".$link;
2653
2654
            $replace_count = 0;
2655
            $full_invitation_text = api_str_ireplace('**link**', $text_link, $invitation_text, $replace_count);
2656
            if ($replace_count < 1) {
2657
                $full_invitation_text = $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
0 ignored issues
show
Bug introduced by
Are you sure $full_invitation_text of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2657
                $full_invitation_text = /** @scrutinizer ignore-type */ $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
Loading history...
2658
            }
2659
        }
2660
2661
        // Sending the mail
2662
        $sender_name = api_get_person_name($_user['firstName'], $_user['lastName'], null, PERSON_NAME_EMAIL_ADDRESS);
2663
        $sender_email = $_user['mail'];
2664
        $sender_user_id = api_get_user_id();
2665
2666
        $replyto = [];
2667
        if ('noreply' === api_get_setting('survey_email_sender_noreply')) {
2668
            $noreply = api_get_setting('noreply_email_address');
2669
            if (!empty($noreply)) {
2670
                $replyto['Reply-to'] = $noreply;
2671
                $sender_name = $noreply;
2672
                $sender_email = $noreply;
2673
                $sender_user_id = null;
2674
            }
2675
        }
2676
2677
        // Optionally: finding the e-mail of the course user
2678
        if (is_numeric($invitedUser)) {
2679
            MessageManager::send_message(
2680
                $invitedUser,
2681
                $invitation_title,
2682
                $full_invitation_text,
2683
                [],
2684
                [],
2685
                null,
2686
                null,
2687
                null,
2688
                null,
2689
                $sender_user_id,
2690
                true
2691
            );
2692
        } else {
2693
            @api_mail_html(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for api_mail_html(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

2693
            /** @scrutinizer ignore-unhandled */ @api_mail_html(

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2694
                '',
2695
                $invitedUser,
2696
                $invitation_title,
2697
                $full_invitation_text,
2698
                $sender_name,
2699
                $sender_email,
2700
                $replyto
2701
            );
2702
        }
2703
    }
2704
2705
    /**
2706
     * This function recalculates the number of users who have been invited and updates the survey table with this
2707
     * value.
2708
     */
2709
    public static function updateInvitedCount(CSurvey $survey, $courseId = 0, $sessionId = 0)
2710
    {
2711
        $surveyId = $survey->getIid();
2712
        $courseId = (int) $courseId;
2713
        $sessionId = (int) $sessionId;
2714
2715
        $courseId = $courseId ?: api_get_course_int_id();
2716
        $sessionId = $sessionId ?: api_get_session_id();
2717
        $sessionCondition = api_get_session_condition($sessionId);
2718
2719
        // Database table definition
2720
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
2721
        $table_survey = Database::get_course_table(TABLE_SURVEY);
2722
2723
        // Counting the number of people that are invited
2724
        $sql = "SELECT count(user_id) as total
2725
                FROM $table_survey_invitation
2726
		        WHERE
2727
		            c_id = $courseId AND
2728
		            survey_id = '".$surveyId."' AND
2729
		            user_id <> ''
2730
		            $sessionCondition
2731
                ";
2732
        $result = Database::query($sql);
2733
        $row = Database::fetch_array($result);
2734
        $total_invited = $row['total'];
2735
2736
        // Updating the field in the survey table
2737
        $sql = "UPDATE $table_survey
2738
		        SET invited = '".Database::escape_string($total_invited)."'
2739
		        WHERE
2740
		            iid = '".$surveyId."'
2741
                ";
2742
        Database::query($sql);
2743
2744
        return $total_invited;
2745
    }
2746
2747
    /**
2748
     * This function gets all the invited users for a given survey code.
2749
     *
2750
     * @return array Array containing the course users and additional users (non course users)
2751
     */
2752
    public static function get_invited_users(CSurvey $survey, $course_code = '', $session_id = 0)
2753
    {
2754
        $session_id = (int) $session_id;
2755
        $surveyId = $survey->getIid();
2756
2757
        $course_code = Database::escape_string($course_code);
2758
        $course_id = api_get_course_int_id();
2759
2760
        if (!empty($course_code)) {
2761
            $course_info = api_get_course_info($course_code);
2762
            if ($course_info) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $course_info of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2763
                $course_id = $course_info['real_id'];
2764
            }
2765
        }
2766
2767
        if (empty($session_id)) {
2768
            $session_id = api_get_session_id();
2769
        }
2770
2771
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
2772
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2773
        $sessionCondition = api_get_session_condition($session_id);
2774
2775
        // Selecting all the invitations of this survey AND the additional emailaddresses (the left join)
2776
        $order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname' : ' ORDER BY lastname, firstname';
2777
        $sql = "SELECT user_id, group_id
2778
				FROM $table_survey_invitation as table_invitation
2779
				WHERE
2780
				    table_invitation.c_id = $course_id AND
2781
                    survey_id = ".$surveyId."
2782
                    $sessionCondition
2783
                ";
2784
2785
        $defaults = [];
2786
        $defaults['course_users'] = [];
2787
        $defaults['additional_users'] = ''; // Textarea
2788
        $defaults['users'] = []; // user and groups
2789
2790
        $result = Database::query($sql);
2791
        while ($row = Database::fetch_array($result)) {
2792
            if (is_numeric($row['user_id'])) {
2793
                $defaults['course_users'][] = $row['user_id'];
2794
                $defaults['users'][] = 'USER:'.$row['user_id'];
2795
            } else {
2796
                if (!empty($row['user_id'])) {
2797
                    $defaults['additional_users'][] = $row['user_id'];
2798
                }
2799
            }
2800
2801
            if (isset($row['group_id']) && !empty($row['group_id'])) {
2802
                $defaults['users'][] = 'GROUP:'.$row['group_id'];
2803
            }
2804
        }
2805
2806
        if (!empty($defaults['course_users'])) {
2807
            $user_ids = implode("','", $defaults['course_users']);
2808
            $sql = "SELECT id FROM $table_user WHERE id IN ('$user_ids') $order_clause";
2809
            $result = Database::query($sql);
2810
            $fixed_users = [];
2811
            while ($row = Database::fetch_array($result)) {
2812
                $fixed_users[] = $row['id'];
2813
            }
2814
            $defaults['course_users'] = $fixed_users;
2815
        }
2816
2817
        if (!empty($defaults['additional_users'])) {
2818
            $defaults['additional_users'] = implode(';', $defaults['additional_users']);
2819
        }
2820
2821
        return $defaults;
2822
    }
2823
2824
    /**
2825
     * Get all the invitations.
2826
     *
2827
     * @param int $surveyId
2828
     *
2829
     * @return array Database rows matching the survey code
2830
     *
2831
     * @author Patrick Cool <[email protected]>, Ghent University
2832
     *
2833
     * @version September 2007
2834
     */
2835
    public static function get_invitations($surveyId)
2836
    {
2837
        $course_id = api_get_course_int_id();
2838
        $sessionId = api_get_session_id();
2839
        // Database table definition
2840
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
2841
2842
        $sql = "SELECT * FROM $table_survey_invitation
2843
		        WHERE
2844
		            c_id = $course_id AND
2845
                    session_id = $sessionId AND
2846
		            survey_id = '".(int) $surveyId."'";
2847
        $result = Database::query($sql);
2848
        $return = [];
2849
        while ($row = Database::fetch_array($result)) {
2850
            $return[$row['user_id']] = $row;
2851
        }
2852
2853
        return $return;
2854
    }
2855
2856
    /**
2857
     * This function displays the form for searching a survey.
2858
     *
2859
     * @author Patrick Cool <[email protected]>, Ghent University
2860
     *
2861
     * @version January 2007
2862
     *
2863
     * @todo consider moving this to surveymanager.inc.lib.php
2864
     */
2865
    public static function display_survey_search_form()
2866
    {
2867
        $url = api_get_path(WEB_CODE_PATH).'survey/survey_list.php?search=advanced&'.api_get_cidreq();
2868
        $form = new FormValidator('search', 'get', $url);
2869
        $form->addHeader(get_lang('Search a survey'));
2870
        $form->addText('keyword_title', get_lang('Title'));
2871
        $form->addText('keyword_code', get_lang('Course code'));
2872
        $form->addSelectLanguage('keyword_language', get_lang('Language'));
2873
        $form->addHidden('cid', api_get_course_int_id());
2874
        $form->addButtonSearch(get_lang('Search'), 'do_search');
2875
        $form->display();
2876
    }
2877
2878
    /**
2879
     * Show table only visible by DRH users.
2880
     */
2881
    public static function displaySurveyListForDrh()
2882
    {
2883
        $parameters = [];
2884
        $parameters['cidReq'] = api_get_course_id();
2885
2886
        // Create a sortable table with survey-data
2887
        $table = new SortableTable(
2888
            'surveys',
2889
            'get_number_of_surveys',
2890
            'get_survey_data_drh',
2891
            2
2892
        );
2893
        $table->set_additional_parameters($parameters);
2894
        $table->set_header(0, '', false);
2895
        $table->set_header(1, get_lang('Survey name'));
2896
        $table->set_header(2, get_lang('Survey code'));
2897
        $table->set_header(3, get_lang('Questions'));
2898
        $table->set_header(4, get_lang('Author'));
2899
        $table->set_header(5, get_lang('Available from'));
2900
        $table->set_header(6, get_lang('Until'));
2901
        $table->set_header(7, get_lang('Invite'));
2902
        $table->set_header(8, get_lang('Anonymous'));
2903
2904
        if ('true' === api_get_setting('survey.allow_mandatory_survey')) {
2905
            $table->set_header(9, get_lang('Mandatory?'));
2906
            $table->set_header(10, get_lang('Edit'), false, 'width="150"');
2907
            $table->set_column_filter(9, 'anonymous_filter');
2908
            $table->set_column_filter(10, 'modify_filter_drh');
2909
        } else {
2910
            $table->set_header(9, get_lang('Edit'), false, 'width="150"');
2911
            $table->set_column_filter(9, 'modify_filter_drh');
2912
        }
2913
2914
        $table->set_column_filter(8, 'anonymous_filter');
2915
        $table->display();
2916
    }
2917
2918
    /**
2919
     * This function displays the sortable table with all the surveys.
2920
     *
2921
     * @author Patrick Cool <[email protected]>, Ghent University
2922
     *
2923
     * @version January 2007
2924
     */
2925
    public static function display_survey_list()
2926
    {
2927
        $parameters = [];
2928
        $parameters['cid'] = api_get_course_int_id();
2929
        $parameters['sid'] = api_get_session_id();
2930
        $parameters['gid'] = api_get_group_id();
2931
        if (isset($_GET['do_search']) && $_GET['do_search']) {
2932
            $message = get_lang('Display search results').'<br />';
2933
            $message .= '<a href="'.api_get_self().'?'.api_get_cidreq().'">'.get_lang('Display all').'</a>';
2934
            echo Display::return_message($message, 'normal', false);
2935
        }
2936
2937
        // Create a sortable table with survey-data
2938
        $table = new SortableTable(
2939
            'surveys',
2940
            'get_number_of_surveys',
2941
            'get_survey_data',
2942
            2
2943
        );
2944
        $table->set_additional_parameters($parameters);
2945
        $table->set_header(0, '', false);
2946
        $table->set_header(1, get_lang('Survey name'));
2947
        $table->set_header(2, get_lang('Survey code'));
2948
        $table->set_header(3, get_lang('Questions'));
2949
        $table->set_header(4, get_lang('Author'));
2950
        $table->set_header(5, get_lang('Available from'));
2951
        $table->set_header(6, get_lang('Until'));
2952
        $table->set_header(7, get_lang('Invite'));
2953
        $table->set_header(8, get_lang('Anonymous'));
2954
2955
        if ('true' === api_get_setting('survey.allow_mandatory_survey')) {
2956
            $table->set_header(9, get_lang('Mandatory?'));
2957
            $table->set_header(10, get_lang('Edit'), false, 'width="150"');
2958
            $table->set_column_filter(8, 'anonymous_filter');
2959
            $table->set_column_filter(10, 'modify_filter');
2960
        } else {
2961
            $table->set_header(9, get_lang('Edit'), false, 'width="150"');
2962
            $table->set_column_filter(9, 'modify_filter');
2963
        }
2964
2965
        $table->set_column_filter(8, 'anonymous_filter');
2966
        $actions = [
2967
            'export_all' => get_lang('ExportResults'),
2968
            'export_by_class' => get_lang('ExportByClass'),
2969
            'send_to_tutors' => get_lang('SendToGroupTutors'),
2970
            'multiplicate' => get_lang('MultiplicateQuestions'),
2971
            'delete' => get_lang('DeleteSurvey'),
2972
        ];
2973
        $table->set_form_actions($actions);
2974
        $table->display();
2975
    }
2976
2977
    /**
2978
     * Survey list for coach.
2979
     */
2980
    public static function display_survey_list_for_coach()
2981
    {
2982
        $parameters = [];
2983
        $parameters['cidReq'] = api_get_course_id();
2984
        if (isset($_GET['do_search'])) {
2985
            $message = get_lang('Display search results').'<br />';
2986
            $message .= '<a href="'.api_get_self().'?'.api_get_cidreq().'">'.get_lang('Display all').'</a>';
2987
            echo Display::return_message($message, 'normal', false);
2988
        }
2989
2990
        // Create a sortable table with survey-data
2991
        $table = new SortableTable(
2992
            'surveys_coach',
2993
            'get_number_of_surveys_for_coach',
2994
            'get_survey_data_for_coach',
2995
            2
2996
        );
2997
        $table->set_additional_parameters($parameters);
2998
        $table->set_header(0, '', false);
2999
        $table->set_header(1, get_lang('Survey name'));
3000
        $table->set_header(2, get_lang('Survey code'));
3001
        $table->set_header(3, get_lang('Questions'));
3002
        $table->set_header(4, get_lang('Author'));
3003
        $table->set_header(5, get_lang('Available from'));
3004
        $table->set_header(6, get_lang('Until'));
3005
        $table->set_header(7, get_lang('Invite'));
3006
        $table->set_header(8, get_lang('Anonymous'));
3007
3008
        if ('true' === api_get_setting('survey.allow_mandatory_survey')) {
3009
            $table->set_header(9, get_lang('Edit'), false, 'width="130"');
3010
            $table->set_header(10, get_lang('Edit'), false, 'width="130"');
3011
            $table->set_column_filter(8, 'anonymous_filter');
3012
            $table->set_column_filter(10, 'modify_filter_for_coach');
3013
        } else {
3014
            $table->set_header(9, get_lang('Edit'), false, 'width="130"');
3015
            $table->set_column_filter(9, 'modify_filter_for_coach');
3016
        }
3017
3018
        $table->set_column_filter(8, 'anonymous_filter');
3019
        $table->display();
3020
    }
3021
3022
    /**
3023
     * Check if the hide_survey_edition configurations setting is enabled.
3024
     *
3025
     * @param string $surveyCode
3026
     *
3027
     * @return bool
3028
     */
3029
    public static function checkHideEditionToolsByCode($surveyCode)
3030
    {
3031
        $hideSurveyEdition = api_get_setting('survey.hide_survey_edition', true);
3032
3033
        if (empty($hideSurveyEdition) || 'false' === $hideSurveyEdition) {
3034
            return false;
3035
        }
3036
3037
        if (is_array($hideSurveyEdition)) {
3038
            if ('*' === $hideSurveyEdition['codes']) {
3039
                return true;
3040
            }
3041
3042
            if (in_array($surveyCode, $hideSurveyEdition['codes'])) {
3043
                return true;
3044
            }
3045
        }
3046
3047
        return false;
3048
    }
3049
3050
    /**
3051
     * This function changes the modify column of the sortable table.
3052
     *
3053
     * @param int  $survey_id the id of the survey
3054
     * @param bool $drh
3055
     *
3056
     * @return string html code that are the actions that can be performed on any survey
3057
     *
3058
     * @author Patrick Cool <[email protected]>, Ghent University
3059
     *
3060
     * @version January 2007
3061
     */
3062
    public static function modify_filter($survey_id, $url_params, $row)
3063
    {
3064
        $repo = Container::getSurveyRepository();
3065
        /** @var CSurvey|null $survey */
3066
        $survey = $repo->find($survey_id);
3067
3068
        if (null === $survey) {
3069
            return '';
3070
        }
3071
3072
        $hideSurveyEdition = self::checkHideEditionToolsByCode($survey->getCode());
3073
3074
        if ($hideSurveyEdition) {
3075
            return '';
3076
        }
3077
3078
        $survey_id = $survey->getIid();
3079
        $actions = [];
3080
        $hideReportingButton = ('true' === api_get_setting('survey.hide_survey_reporting_button'));
3081
        $codePath = api_get_path(WEB_CODE_PATH);
3082
        $params = [];
3083
        parse_str(api_get_cidreq(), $params);
3084
3085
        $reportingLink = Display::url(
3086
            Display::getMdiIcon(ToolIcon::TRACKING, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Reporting')),
3087
            $codePath.'survey/reporting.php?'.http_build_query($params + ['survey_id' => $survey_id])
3088
        );
3089
3090
        if (!$row['can_edit']) {
3091
            return $hideReportingButton ? '-' : $reportingLink;
3092
        }
3093
3094
        $type = $survey->getSurveyType();
3095
3096
        // Coach can see that only if the survey is in his session
3097
        if (api_is_allowed_to_edit() || api_is_element_in_the_session(TOOL_SURVEY, $survey_id)) {
3098
            $configUrl = $codePath.'survey/create_new_survey.php?'.
3099
                http_build_query($params + ['action' => 'edit', 'survey_id' => $survey_id]);
3100
            $editUrl = $codePath.'survey/survey.php?'.
3101
                http_build_query($params + ['survey_id' => $survey_id]);
3102
            if (3 == $type) {
3103
                $configUrl = $codePath.'survey/edit_meeting.php?'.
3104
                    http_build_query($params + ['action' => 'edit', 'survey_id' => $survey_id]);
3105
            }
3106
3107
            $actions[] = Display::url(
3108
                Display::getMdiIcon(ActionIcon::EDIT, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Edit')),
3109
                $editUrl
3110
            );
3111
            $actions[] = Display::url(
3112
                Display::getMdiIcon(ToolIcon::SETTINGS, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Configure')),
3113
                $configUrl
3114
            );
3115
3116
            if (SurveyManager::survey_generation_hash_available()) {
3117
                $actions[] = Display::url(
3118
                    Display::getMdiIcon(ToolIcon::LINK, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Generate survey access link')),
3119
                    $codePath.'survey/generate_link.php?'.http_build_query($params + ['survey_id' => $survey_id])
3120
                );
3121
            }
3122
3123
            if (3 != $type) {
3124
                $actions[] = Display::url(
3125
                    Display::getMdiIcon(ActionIcon::COPY_CONTENT, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Copy survey')),
3126
                    $codePath.'survey/copy_survey.php?'.http_build_query($params + ['survey_id' => $survey_id])
3127
                );
3128
3129
                $actions[] = Display::url(
3130
                    Display::getMdiIcon(ObjectIcon::MULTI_ELEMENT, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Duplicate survey')),
3131
                    $codePath.'survey/survey_list.php?'
3132
                    .http_build_query($params + ['action' => 'copy_survey', 'survey_id' => $survey_id])
3133
                );
3134
3135
                $actions[] = Display::url(
3136
                    Display::getMdiIcon('view-grid-plus-outline', 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Multiplicate questions')),
3137
                    $codePath.'survey/survey_list.php?'
3138
                    .http_build_query($params + ['action' => 'multiplicate', 'survey_id' => $survey_id])
3139
                );
3140
3141
                $actions[] = Display::url(
3142
                    Display::getMdiIcon('view-grid-plus-outline', 'ch-tool-icon-disabled', null, ICON_SIZE_SMALL, get_lang('RemoveMultiplicate questions')),
3143
                    $codePath.'survey/survey_list.php?'
3144
                    .http_build_query($params + ['action' => 'remove_multiplicate', 'survey_id' => $survey_id])
3145
                );
3146
3147
                $warning = addslashes(api_htmlentities(get_lang('Empty survey').'?', ENT_QUOTES));
3148
                $actions[] = Display::url(
3149
                    Display::getMdiIcon(ActionIcon::RESET, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Empty survey')),
3150
                    $codePath.'survey/survey_list.php?'
3151
                    .http_build_query($params + ['action' => 'empty', 'survey_id' => $survey_id]),
3152
                    [
3153
                        'onclick' => "javascript: if (!confirm('".$warning."')) return false;",
3154
                    ]
3155
                );
3156
            }
3157
        }
3158
3159
        if (3 != $type) {
3160
            $actions[] = Display::url(
3161
                Display::getMdiIcon(ActionIcon::PREVIEW_CONTENT, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Preview')),
3162
                $codePath.'survey/preview.php?'.http_build_query($params + ['survey_id' => $survey_id])
3163
            );
3164
        }
3165
3166
        $actions[] = Display::url(
3167
            Display::getMdiIcon(StateIcon::MAIL_NOTIFICATION, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Publish')),
3168
            $codePath.'survey/survey_invite.php?'.http_build_query($params + ['survey_id' => $survey_id])
3169
        );
3170
3171
        $extraFieldValue = new ExtraFieldValue('survey');
3172
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($survey_id, 'group_id');
3173
        if ($groupData && !empty($groupData['value'])) {
3174
            $actions[] = Display::url(
3175
                Display::getMdiIcon(ObjectIcon::TEACHER, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('SendToGroupTutors')),
3176
                $codePath.'survey/survey_list.php?action=send_to_tutors&'.http_build_query($params + ['survey_id' => $survey_id])
3177
            );
3178
        }
3179
3180
        if (3 != $type) {
3181
            $actions[] = $hideReportingButton ? null : $reportingLink;
3182
        }
3183
3184
        if (api_is_allowed_to_edit() ||
3185
            api_is_element_in_the_session(TOOL_SURVEY, $survey_id)
3186
        ) {
3187
            $actions[] = self::getAdditionalTeacherActions($survey_id);
3188
3189
            $warning = addslashes(api_htmlentities(get_lang('Delete survey').'?', ENT_QUOTES));
3190
            $actions[] = Display::url(
3191
                Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Delete')),
3192
                $codePath.'survey/survey_list.php?'
3193
                .http_build_query($params + ['action' => 'delete', 'survey_id' => $survey_id]),
3194
                [
3195
                    'onclick' => "javascript: if (!confirm('".$warning."')) return false;",
3196
                ]
3197
            );
3198
        }
3199
3200
        return implode(PHP_EOL, $actions);
3201
    }
3202
3203
    /**
3204
     * Get the additional actions added in survey_additional_teacher_modify_actions configuration.
3205
     *
3206
     * @param int $surveyId
3207
     * @param int $iconSize
3208
     *
3209
     * @return string
3210
     */
3211
    public static function getAdditionalTeacherActions($surveyId, $iconSize = ICON_SIZE_SMALL)
3212
    {
3213
        $additionalActions = api_get_setting('survey.survey_additional_teacher_modify_actions', true) ?: [];
3214
3215
        if (empty($additionalActions) || ('false' === $additionalActions)) {
3216
            return '';
3217
        }
3218
3219
        $action = '';
3220
        if (is_array($additionalActions)) {
3221
            $actions = [];
3222
            foreach ($additionalActions as $additionalAction) {
3223
                $actions[] = call_user_func(
3224
                    $additionalAction,
3225
                    ['survey_id' => $surveyId, 'icon_size' => $iconSize]
3226
                );
3227
            }
3228
            $action = implode(PHP_EOL, $actions);
3229
        }
3230
3231
3232
        return $action;
3233
    }
3234
3235
    /**
3236
     * @param int $survey_id
3237
     *
3238
     * @return string
3239
     */
3240
    public static function modify_filter_for_coach($survey_id)
3241
    {
3242
        $survey_id = (int) $survey_id;
3243
        $actions = [];
3244
        $codePath = api_get_path(WEB_CODE_PATH);
3245
        $params = [];
3246
        parse_str(api_get_cidreq(), $params);
3247
        $actions[] = Display::url(
3248
            Display::getMdiIcon(ActionIcon::PREVIEW_CONTENT, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Preview')),
3249
            $codePath.'survey/preview.php?'.http_build_query($params + ['survey_id' => $survey_id])
3250
        );
3251
        $actions[] = Display::url(
3252
            Display::getMdiIcon(StateIcon::MAIL_NOTIFICATION, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Publish')),
3253
            $codePath.'survey/survey_invite.php?'.http_build_query($params + ['survey_id' => $survey_id])
3254
        );
3255
        $warning = addslashes(api_htmlentities(get_lang('Empty survey').'?', ENT_QUOTES));
3256
        $actions[] = Display::url(
3257
            Display::getMdiIcon(ActionIcon::RESET, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Empty survey')),
3258
            $codePath.'survey/survey_list.php?'
3259
                .http_build_query($params + ['action' => 'empty', 'survey_id' => $survey_id]),
3260
            [
3261
                'onclick' => "javascript: if(!confirm('".$warning."')) return false;",
3262
            ]
3263
        );
3264
3265
        return implode(PHP_EOL, $actions);
3266
    }
3267
3268
    /**
3269
     * Returns "yes" when given parameter is one, "no" for any other value.
3270
     *
3271
     * @param int Whether anonymous or not
3272
     *
3273
     * @return string "Yes" or "No" in the current language
3274
     */
3275
    public static function anonymous_filter($anonymous)
3276
    {
3277
        if (1 == $anonymous) {
3278
            return get_lang('Yes');
3279
        }
3280
3281
        return get_lang('No');
3282
    }
3283
3284
    public static function survey_search_restriction()
3285
    {
3286
        if (isset($_GET['do_search'])) {
3287
            if ('' != $_GET['keyword_title']) {
3288
                $search_term[] = 'title like "%" \''.Database::escape_string($_GET['keyword_title']).'\' "%"';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$search_term was never initialized. Although not strictly required by PHP, it is generally a good practice to add $search_term = array(); before regardless.
Loading history...
3289
            }
3290
            if ('' != $_GET['keyword_code']) {
3291
                $search_term[] = 'code =\''.Database::escape_string($_GET['keyword_code']).'\'';
3292
            }
3293
            if ('%' != $_GET['keyword_language']) {
3294
                $search_term[] = 'lang =\''.Database::escape_string($_GET['keyword_language']).'\'';
3295
            }
3296
            $my_search_term = (null == $search_term) ? [] : $search_term;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $search_term does not seem to be defined for all execution paths leading up to this point.
Loading history...
3297
            $search_restriction = implode(' AND ', $my_search_term);
3298
3299
            return $search_restriction;
3300
        } else {
3301
            return false;
3302
        }
3303
    }
3304
3305
    public static function get_number_of_surveys()
3306
    {
3307
        $repo = Container::getSurveyRepository();
3308
        $course = api_get_course_entity();
3309
        $session = api_get_session_entity();
3310
        $qb = $repo->findAllByCourse($course, $session);
3311
3312
        return $repo->getCount($qb);
3313
3314
        /*$table_survey = Database::get_course_table(TABLE_SURVEY);
3315
        $course_id = api_get_course_int_id();
3316
3317
        $search_restriction = self::survey_search_restriction();
3318
        if ($search_restriction) {
3319
            $search_restriction = 'WHERE c_id = '.$course_id.' AND '.$search_restriction;
3320
        } else {
3321
            $search_restriction = "WHERE c_id = $course_id";
3322
        }
3323
        $sql = "SELECT count(iid) AS total_number_of_items
3324
                FROM $table_survey $search_restriction";
3325
        $res = Database::query($sql);
3326
        $obj = Database::fetch_object($res);
3327
3328
        return $obj->total_number_of_items;*/
3329
    }
3330
3331
    /**
3332
     * @return int
3333
     */
3334
    public static function get_number_of_surveys_for_coach()
3335
    {
3336
        $repo = Container::getSurveyRepository();
3337
        $course = api_get_course_entity();
3338
        $session = api_get_session_entity();
3339
        $qb = $repo->findAllByCourse($course, $session);
3340
3341
        return $repo->getCount($qb);
3342
3343
        /*$survey_tree = new SurveyTree();
3344
        return count($survey_tree->surveylist);*/
3345
    }
3346
3347
    /**
3348
     * This function gets all the survey data that is to be displayed in the sortable table.
3349
     *
3350
     * @param int    $from
3351
     * @param int    $number_of_items
3352
     * @param int    $column
3353
     * @param string $direction
3354
     * @param bool   $isDrh
3355
     *
3356
     * @return array
3357
     *
3358
     * @author Patrick Cool <[email protected]>, Ghent University
3359
     * @author Julio Montoya <[email protected]>, Beeznest - Adding intvals
3360
     *
3361
     * @version January 2007
3362
     */
3363
    public static function get_survey_data(
3364
        int    $from,
3365
        int    $number_of_items,
3366
        int    $column,
3367
        string $direction,
3368
        bool $isDrh = false
3369
    ): array {
3370
        $repo = Container::getSurveyRepository();
3371
        $course = api_get_course_entity();
3372
        $sessionId = api_get_session_id();
3373
        $session = api_get_session_entity();
3374
3375
        $qb = $repo->findAllByCourse($course, $session);
3376
        /** @var CSurvey[] $surveys */
3377
        $surveys = $qb->getQuery()->getResult();
3378
3379
        $mandatoryAllowed = ('true' === api_get_setting('survey.allow_mandatory_survey'));
3380
3381
        $from = (int) $from;
3382
        $number_of_items = (int) $number_of_items;
3383
        $column = (int) $column;
3384
        if (!in_array(strtolower($direction), ['asc', 'desc'])) {
3385
            $direction = 'asc';
3386
        }
3387
3388
        $efv = new ExtraFieldValue('survey');
3389
        $list = [];
3390
3391
        if ($sessionId > 0) {
3392
            foreach ($surveys as $survey) {
3393
                $surveySession = $survey->getFirstResourceLink()->getSession();
3394
                if ($surveySession && $surveySession->getId() == $sessionId) {
3395
                    $list[] = self::prepare_survey_array($survey, $efv, $mandatoryAllowed, $isDrh);
3396
                }
3397
            }
3398
3399
            $lpRepo = Container::getLpRepository();
3400
            $lpsInSessionQb = $lpRepo->findAllByCourse($course, $session);
3401
            $lpsInSession = $lpsInSessionQb->getQuery()->getResult();
3402
3403
            foreach ($lpsInSession as $lpInSession) {
3404
                $lpInSessionSession = $lpInSession->getFirstResourceLink()->getSession();
3405
3406
                if ($lpInSessionSession && $lpInSessionSession->getId() == $sessionId) {
3407
                    foreach ($lpInSession->getItems() as $sessionItem) {
3408
                        if ($sessionItem->getItemType() === 'survey') {
3409
                            $itemId = (int) $sessionItem->getPath();
3410
                            $survey = $repo->find($itemId);
3411
                            if ($survey && $survey->getFirstResourceLink()->getSession() == null) {
3412
                                $list[] = self::prepare_survey_array($survey, $efv, $mandatoryAllowed, $isDrh, false);
3413
                            }
3414
                        }
3415
                    }
3416
                }
3417
            }
3418
        } else {
3419
            foreach ($surveys as $survey) {
3420
                $list[] = self::prepare_survey_array($survey, $efv, $mandatoryAllowed, $isDrh);
3421
            }
3422
        }
3423
3424
        return $list;
3425
    }
3426
3427
3428
    private static function prepare_survey_array($survey, $efv, $mandatoryAllowed, $isDrh, $canEdit = true) {
3429
        $array = [];
3430
        $surveyId = $survey->getIid();
3431
        $array[0] = $surveyId;
3432
        $type = $survey->getSurveyType();
3433
3434
        $title = $survey->getTitle();
3435
        if (self::checkHideEditionToolsByCode($survey->getCode())) {
3436
            $array[1] = $title;
3437
        } else {
3438
            // Doodle
3439
            if (3 == $type) {
3440
                $array[1] = Display::url(
3441
                    $title,
3442
                    api_get_path(WEB_CODE_PATH).'survey/meeting.php?survey_id='.$surveyId.'&'.api_get_cidreq()
3443
                );
3444
            } else {
3445
                $array[1] = Display::url(
3446
                    $title,
3447
                    api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.$surveyId.'&'.api_get_cidreq()
3448
                );
3449
            }
3450
        }
3451
3452
        $array[2] = $survey->getCode();
3453
        $array[3] = $survey->getQuestions()->count();
3454
        $array[4] = UserManager::formatUserFullName($survey->getCreator());
3455
3456
        $array[5] = '';
3457
        $from = $survey->getAvailFrom() ? $survey->getAvailFrom()->format('Y-m-d H:i:s') : null;
3458
        if (null !== $from) {
3459
            $array[5] = api_convert_and_format_date(
3460
                $from,
3461
                DATE_TIME_FORMAT_LONG
3462
            );
3463
        }
3464
3465
        $array[6] = '';
3466
        $till = $survey->getAvailTill() ? $survey->getAvailTill()->format('Y-m-d H:i:s') : null;
3467
        if (null !== $till) {
3468
            $array[6] = api_convert_and_format_date(
3469
                $till,
3470
                DATE_TIME_FORMAT_LONG
3471
            );
3472
        }
3473
3474
        $array[7] = Display::url(
3475
                $survey->getAnswered(),
3476
                api_get_path(WEB_CODE_PATH).'survey/survey_invitation.php?view=answered&survey_id='.$surveyId.'&'.api_get_cidreq()
3477
            ).' / '.
3478
            Display::url(
3479
                $survey->getInvited(),
3480
                api_get_path(WEB_CODE_PATH).'survey/survey_invitation.php?view=invited&survey_id='.$surveyId.'&'.api_get_cidreq()
3481
            );
3482
3483
        $array[8] = $survey->getAnonymous();
3484
        if ($mandatoryAllowed) {
3485
            $efvMandatory = $efv->get_values_by_handler_and_field_variable(
3486
                $surveyId,
3487
                'is_mandatory'
3488
            );
3489
3490
            $array[9] = $efvMandatory ? $efvMandatory['value'] : 0;
3491
            $array[10] = $surveyId;
3492
        } else {
3493
            $array[9] = $surveyId;
3494
        }
3495
3496
        if ($isDrh) {
3497
            $array[1] = $title;
3498
            $array[7] = strip_tags($survey->getInvited());
3499
        }
3500
3501
        $array['can_edit'] = $canEdit;
3502
3503
        return $array;
3504
    }
3505
3506
    /**
3507
     * @param $from
3508
     * @param $number_of_items
3509
     * @param $column
3510
     * @param $direction
3511
     *
3512
     * @return array
3513
     */
3514
    public static function get_survey_data_for_coach($from, $number_of_items, $column, $direction)
3515
    {
3516
        $mandatoryAllowed = ('true' === api_get_setting('survey.allow_mandatory_survey'));
3517
        $repo = Container::getSurveyRepository();
3518
        $qb = $repo->findAllByCourse(
3519
            api_get_course_entity(),
3520
            api_get_session_entity(),
3521
            null,
3522
            null,
3523
            api_get_user_entity()
3524
        );
3525
3526
        /** @var CSurvey[] $surveys */
3527
        $surveys = $qb->getQuery()->getResult();
3528
        $list = [];
3529
        foreach ($surveys as $survey) {
3530
            $list[] = $survey->getIid();
3531
        }
3532
        $list_condition = '';
3533
        if (count($list) > 0) {
3534
            $list_condition = " AND survey.iid IN (".implode(',', $list).") ";
3535
        }
3536
        $from = (int) $from;
3537
        $number_of_items = (int) $number_of_items;
3538
        $column = (int) $column;
3539
        if (!in_array(strtolower($direction), ['asc', 'desc'])) {
3540
            $direction = 'asc';
3541
        }
3542
3543
        $table_survey = Database::get_course_table(TABLE_SURVEY);
3544
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
3545
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
3546
        $course_id = api_get_course_int_id();
3547
        $efv = new ExtraFieldValue('survey');
3548
3549
        $sql = "
3550
            SELECT
3551
            survey.iid AS col0,
3552
                survey.title AS col1,
3553
                survey.code AS col2,
3554
                count(survey_question.iid) AS col3,
3555
        "
3556
            .(api_is_western_name_order()
3557
                ? "CONCAT(user.firstname, ' ', user.lastname)"
3558
                : "CONCAT(user.lastname, ' ', user.firstname)")
3559
            ."	AS col4,
3560
                survey.avail_from AS col5,
3561
                survey.avail_till AS col6,
3562
                CONCAT('<a href=\"survey_invitation.php?view=answered&survey_id=',survey.iid,'\">',survey.answered,'</a> / <a href=\"survey_invitation.php?view=invited&survey_id=',survey.iid,'\">',survey.invited, '</a>') AS col7,
3563
                survey.anonymous AS col8,
3564
                survey.iid AS col9
3565
            FROM $table_survey survey
3566
            LEFT JOIN $table_survey_question survey_question
3567
            ON (survey.iid = survey_question.survey_id),
3568
            $table_user user
3569
            WHERE survey.author = user.id AND survey.c_id = $course_id $list_condition
3570
        ";
3571
        $sql .= ' GROUP BY survey.iid';
3572
        $sql .= " ORDER BY col$column $direction ";
3573
        $sql .= " LIMIT $from,$number_of_items";
3574
3575
        $res = Database::query($sql);
3576
        $surveys = [];
3577
        while ($survey = Database::fetch_array($res)) {
3578
            $survey['col5'] = api_convert_and_format_date(
3579
                $survey['col5'],
3580
                DATE_TIME_FORMAT_LONG
3581
            );
3582
            $survey['col6'] = api_convert_and_format_date(
3583
                $survey['col6'],
3584
                DATE_TIME_FORMAT_LONG
3585
            );
3586
3587
            if ($mandatoryAllowed) {
3588
                $survey['col10'] = $survey['col9'];
3589
                $efvMandatory = $efv->get_values_by_handler_and_field_variable(
3590
                    $survey['col9'],
3591
                    'is_mandatory'
3592
                );
3593
                $survey['col9'] = $efvMandatory['value'];
3594
            }
3595
            $surveys[] = $survey;
3596
        }
3597
3598
        return $surveys;
3599
    }
3600
3601
    /**
3602
     * Display all the active surveys for the given course user.
3603
     *
3604
     * @param int $user_id
3605
     *
3606
     * @author Patrick Cool <[email protected]>, Ghent University
3607
     *
3608
     * @version April 2007
3609
     */
3610
    public static function getSurveyList($user_id)
3611
    {
3612
        $course = api_get_course_entity();
3613
        $_course = api_get_course_info();
3614
        $course_id = $_course['real_id'];
3615
        $user_id = (int) $user_id;
3616
        $sessionId = api_get_session_id();
3617
        $mandatoryAllowed = ('true' === api_get_setting('survey.allow_mandatory_survey'));
3618
3619
        // Database table definitions
3620
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
3621
        $table_survey = Database::get_course_table(TABLE_SURVEY);
3622
3623
        echo '<table id="list-survey" class="table">';
3624
        echo '<thead>';
3625
        echo '<tr>';
3626
        echo '	<th>'.get_lang('Survey name').'</th>';
3627
        echo '	<th class="text-center">'.get_lang('Anonymous').'</th>';
3628
        if ($mandatoryAllowed) {
3629
            echo '<th class="text-center">'.get_lang('Mandatory?').'</th>';
3630
        }
3631
        echo '</tr>';
3632
        echo '</thead>';
3633
        echo '<tbody>';
3634
3635
        /** @var \DateTime $now */
3636
        $now = api_get_utc_datetime(null, false, true);
3637
        $filterDate = $now->format('Y-m-d H:i');
3638
        $sessionCondition = api_get_session_condition($sessionId, true, false, 'survey_invitation.session_id');
3639
3640
        $sql = "SELECT
3641
                    survey_invitation.answered,
3642
                    survey_invitation.invitation_code,
3643
                    survey_invitation.session_id,
3644
                    survey.title,
3645
                    survey.visible_results,
3646
                    survey.iid,
3647
                    survey.anonymous
3648
                FROM $table_survey survey
3649
                INNER JOIN
3650
                $table_survey_invitation survey_invitation
3651
                ON (
3652
                    survey.iid = survey_invitation.survey_id
3653
                )
3654
				WHERE
3655
                    survey_invitation.user_id = $user_id AND
3656
                    survey.avail_from <= '$filterDate' AND
3657
                    survey.avail_till >= '$filterDate' AND
3658
                    survey_invitation.c_id = $course_id
3659
                    $sessionCondition
3660
				";
3661
        $result = Database::query($sql);
3662
        $efv = new ExtraFieldValue('survey');
3663
        $surveyIds = [];
3664
        $repo = Container::getSurveyRepository();
3665
        while ($row = Database::fetch_assoc($result)) {
3666
            $surveyId = $row['iid'];
3667
            if (in_array($surveyId, $surveyIds)) {
3668
                continue;
3669
            }
3670
3671
            /** @var CSurvey $survey */
3672
            $survey = $repo->find($surveyId);
3673
3674
            echo '<tr>';
3675
            if (0 == $survey->getAnswered()) {
3676
                echo '<td>';
3677
                $url = self::generateFillSurveyLink($survey, $row['invitation_code'], $course, $row['session_id']);
3678
                $icon = Display::getMdiIcon(ToolIcon::SURVEY, 'ch-tool-icon', null, ICON_SIZE_TINY, get_lang('ClickHereToAnswerTheSurvey'));
3679
                echo '<a href="'.$url.'">
3680
                    '.$icon
3681
                    .$row['title']
3682
                    .'</a></td>';
3683
            } else {
3684
                $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
3685
                    $user_id,
3686
                    $_course
3687
                );
3688
                $icon = Display::getMdiIcon(ObjectIcon::SURVEY, 'ch-tool-icon-disabled', null, ICON_SIZE_TINY, get_lang('SurveysDone'));
3689
                $showLink = (!api_is_allowed_to_edit(false, true) || $isDrhOfCourse)
3690
                    && SURVEY_VISIBLE_TUTOR != $row['visible_results'];
3691
3692
                echo '<td>';
3693
                echo $showLink
3694
                    ? Display::url(
3695
                        $icon.PHP_EOL.$row['title'],
3696
                        api_get_path(WEB_CODE_PATH).'survey/reporting.php?'.api_get_cidreq().'&'.http_build_query([
3697
                            'action' => 'questionreport',
3698
                            'survey_id' => $surveyId,
3699
                        ])
3700
                    )
3701
                    : $icon.PHP_EOL.$row['title'];
3702
                echo '</td>';
3703
            }
3704
            echo '<td class="text-center">';
3705
            echo 1 == $row['anonymous'] ? get_lang('Yes') : get_lang('No');
3706
            echo '</td>';
3707
            if ($mandatoryAllowed) {
3708
                $efvMandatory = $efv->get_values_by_handler_and_field_variable(
3709
                    $row['survey_id'],
3710
                    'is_mandatory'
3711
                );
3712
                echo '<td class="text-center">'.($efvMandatory['value'] ? get_lang('Yes') : get_lang('No')).'</td>';
3713
            }
3714
            echo '</tr>';
3715
            $surveyIds[] = $surveyId;
3716
        }
3717
        echo '</tbody>';
3718
        echo '</table>';
3719
    }
3720
3721
    /**
3722
     * Creates a multi array with the user fields that we can show.
3723
     * We look the visibility with the api_get_setting function
3724
     * The username is always NOT able to change it.
3725
     *
3726
     * @author Julio Montoya Armas <[email protected]>, Chamilo: Personality Test modification
3727
     *
3728
     * @return array array[value_name][name], array[value_name][visibilty]
3729
     */
3730
    public static function make_field_list()
3731
    {
3732
        //	LAST NAME and FIRST NAME
3733
        $field_list_array = [];
3734
        $field_list_array['lastname']['name'] = get_lang('Last name');
3735
        $field_list_array['firstname']['name'] = get_lang('First name');
3736
3737
        if ('true' != api_get_setting('profile', 'name')) {
3738
            $field_list_array['firstname']['visibility'] = 0;
3739
            $field_list_array['lastname']['visibility'] = 0;
3740
        } else {
3741
            $field_list_array['firstname']['visibility'] = 1;
3742
            $field_list_array['lastname']['visibility'] = 1;
3743
        }
3744
3745
        $field_list_array['username']['name'] = get_lang('Username');
3746
        $field_list_array['username']['visibility'] = 0;
3747
3748
        //	OFFICIAL CODE
3749
        $field_list_array['official_code']['name'] = get_lang('OfficialCourse code');
3750
3751
        if ('true' != api_get_setting('profile', 'officialcode')) {
3752
            $field_list_array['official_code']['visibility'] = 1;
3753
        } else {
3754
            $field_list_array['official_code']['visibility'] = 0;
3755
        }
3756
3757
        // EMAIL
3758
        $field_list_array['email']['name'] = get_lang('e-mail');
3759
        if ('true' != api_get_setting('profile', 'email')) {
3760
            $field_list_array['email']['visibility'] = 1;
3761
        } else {
3762
            $field_list_array['email']['visibility'] = 0;
3763
        }
3764
3765
        // PHONE
3766
        $field_list_array['phone']['name'] = get_lang('Phone');
3767
        if ('true' != api_get_setting('profile', 'phone')) {
3768
            $field_list_array['phone']['visibility'] = 0;
3769
        } else {
3770
            $field_list_array['phone']['visibility'] = 1;
3771
        }
3772
        //	LANGUAGE
3773
        $field_list_array['language']['name'] = get_lang('Language');
3774
        if ('true' != api_get_setting('profile', 'language')) {
3775
            $field_list_array['language']['visibility'] = 0;
3776
        } else {
3777
            $field_list_array['language']['visibility'] = 1;
3778
        }
3779
3780
        // EXTRA FIELDS
3781
        $extra = UserManager::get_extra_fields(0, 50, 5, 'ASC');
3782
3783
        foreach ($extra as $id => $field_details) {
3784
            if (0 == $field_details[6]) {
3785
                continue;
3786
            }
3787
            switch ($field_details[2]) {
3788
                case UserManager::USER_FIELD_TYPE_TEXT:
3789
                    $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3790
                    if (0 == $field_details[7]) {
3791
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3792
                    } else {
3793
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3794
                    }
3795
                    break;
3796
                case UserManager::USER_FIELD_TYPE_TEXTAREA:
3797
                    $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3798
                    if (0 == $field_details[7]) {
3799
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3800
                    } else {
3801
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3802
                    }
3803
                    break;
3804
                case UserManager::USER_FIELD_TYPE_RADIO:
3805
                    $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3806
                    if (0 == $field_details[7]) {
3807
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3808
                    } else {
3809
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3810
                    }
3811
                    break;
3812
                case UserManager::USER_FIELD_TYPE_SELECT:
3813
                    $get_lang_variables = false;
3814
                    if (in_array(
3815
                        $field_details[1],
3816
                        ['mail_notify_message', 'mail_notify_invitation', 'mail_notify_group_message']
3817
                    )
3818
                    ) {
3819
                        $get_lang_variables = true;
3820
                    }
3821
3822
                    if ($get_lang_variables) {
3823
                        $field_list_array['extra_'.$field_details[1]]['name'] = get_lang($field_details[3]);
3824
                    } else {
3825
                        $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3826
                    }
3827
3828
                    if (0 == $field_details[7]) {
3829
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3830
                    } else {
3831
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3832
                    }
3833
                    break;
3834
                case UserManager::USER_FIELD_TYPE_SELECT_MULTIPLE:
3835
                    $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3836
                    if (0 == $field_details[7]) {
3837
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3838
                    } else {
3839
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3840
                    }
3841
                    break;
3842
                case UserManager::USER_FIELD_TYPE_DATE:
3843
                    $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3844
                    if (0 == $field_details[7]) {
3845
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3846
                    } else {
3847
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3848
                    }
3849
                    break;
3850
                case UserManager::USER_FIELD_TYPE_DATETIME:
3851
                    $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3852
                    if (0 == $field_details[7]) {
3853
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3854
                    } else {
3855
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3856
                    }
3857
                    break;
3858
                case UserManager::USER_FIELD_TYPE_DOUBLE_SELECT:
3859
                    $field_list_array['extra_'.$field_details[1]]['name'] = $field_details[3];
3860
                    if (0 == $field_details[7]) {
3861
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 0;
3862
                    } else {
3863
                        $field_list_array['extra_'.$field_details[1]]['visibility'] = 1;
3864
                    }
3865
                    break;
3866
                case UserManager::USER_FIELD_TYPE_DIVIDER:
3867
                    //$form->addElement('static',$field_details[1], '<br /><strong>'.$field_details[3].'</strong>');
3868
                    break;
3869
            }
3870
        }
3871
3872
        return $field_list_array;
3873
    }
3874
3875
    /**
3876
     * Display survey question chart.
3877
     *
3878
     * @param array  $chartData
3879
     * @param bool   $hasSerie         Tells if the chart has a serie. False by default
3880
     * @param string $chartContainerId
3881
     *
3882
     * @return string (direct output)
3883
     */
3884
    public static function drawChart($chartData, $hasSerie = false, $chartContainerId = 'chartContainer', $loadLibs = true)
3885
    {
3886
        $htmlChart = '';
3887
        //if (api_browser_support('svg')) {
3888
        if (true) {
3889
            $serie = [];
3890
            $order = [];
3891
            $data = '';
3892
            foreach ($chartData as $chartDataElement) {
3893
                $data .= '{"';
3894
                $option = str_replace(["\n", "\r"], '', $chartDataElement['option']);
3895
                $serieValue = isset($chartDataElement['serie']) ? $chartDataElement['serie'] : null;
3896
                if (!$hasSerie) {
3897
                    $data .= get_lang("Option").'":"'.$option.'", "';
3898
                    array_push($order, $option);
3899
                } else {
3900
                    if (!is_array($serieValue)) {
3901
                        $data .=
3902
                            get_lang("Option").'":"'.$serieValue.'", "'.
3903
                            get_lang("Score").'":"'.$option.'", "';
3904
                        array_push($serie, $serieValue);
3905
                    } else {
3906
                        $data .=
3907
                            get_lang("Serie").'":"'.$serieValue[0].'", "'.
3908
                            get_lang("Option").'":"'.$serieValue[1].'", "'.
3909
                            get_lang("Score").'":"'.$option.'", "';
3910
                    }
3911
                }
3912
                $data .= get_lang("Votes").'":"'.$chartDataElement['votes'].'"},';
3913
                rtrim($data, ",");
3914
            }
3915
            if ($loadLibs) {
3916
                $htmlChart .= api_get_js('d3/d3.v3.5.4.min.js');
3917
                $htmlChart .= api_get_js('dimple.v2.1.2.min.js');
3918
            }
3919
3920
            $htmlChart .= '
3921
            <script>
3922
                var svg = dimple.newSvg("#'.$chartContainerId.'", 600, 400);
3923
                var data = ['.$data.'];
3924
                var myChart = new dimple.chart(svg, data);
3925
                myChart.setBounds(50, 30, 550, 300);
3926
                var yAxis = myChart.addMeasureAxis("y", "'.get_lang('Votes').'");
3927
                yAxis.fontSize = "14px";
3928
            ';
3929
            if (!$hasSerie) {
3930
                $htmlChart .= '
3931
                    var xAxisCategory = myChart.addCategoryAxis("x", "'.get_lang("Option").'");
3932
                    xAxisCategory.fontSize = "14px";
3933
                    xAxisCategory.addOrderRule('.json_encode($order).');
3934
                    myChart.addSeries("'.get_lang("Option").'", dimple.plot.bar);';
3935
            } else {
3936
                if (!is_array($chartDataElement['serie'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $chartDataElement seems to be defined by a foreach iteration on line 3892. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
3937
                    $serie = array_values(array_unique($serie));
3938
                    $htmlChart .= '
3939
                        var xAxisCategory =
3940
                        myChart.addCategoryAxis("x", ["'.get_lang('Option').'","'.get_lang("Score").'"]);
3941
                        xAxisCategory.addOrderRule('.json_encode($serie).');
3942
                        xAxisCategory.addGroupOrderRule("'.get_lang('Score').'");
3943
3944
                        myChart.addSeries("'.get_lang('Option').'", dimple.plot.bar);';
3945
                } else {
3946
                    $htmlChart .= '
3947
                        myChart.addCategoryAxis("x", ["'.get_lang('Option').'","'.get_lang("Score").'"]);
3948
                        myChart.addSeries("'.get_lang('Serie').'", dimple.plot.bar);';
3949
                }
3950
            }
3951
            $htmlChart .= 'myChart.draw();';
3952
            $htmlChart .= '</script>';
3953
        }
3954
3955
        return $htmlChart;
3956
    }
3957
3958
    /**
3959
     * Set a flag to the current survey as answered by the current user.
3960
     */
3961
    public static function flagSurveyAsAnswered(string $surveyCode, int $courseId): void
3962
    {
3963
        $currentUserId = api_get_user_id();
3964
        $flag = sprintf('%s-%s-%d', $courseId, $surveyCode, $currentUserId);
3965
3966
        if (!isset($_SESSION['filled_surveys'])) {
3967
            $_SESSION['filled_surveys'] = [];
3968
        }
3969
3970
        $_SESSION['filled_surveys'][] = $flag;
3971
    }
3972
3973
    /**
3974
     * Check whether a survey was answered by the current user.
3975
     */
3976
    public static function isSurveyAnsweredFlagged(string $surveyCode, int $courseId): bool
3977
    {
3978
        $currentUserId = api_get_user_id();
3979
        $flagToCheck = sprintf('%s-%s-%d', $courseId, $surveyCode, $currentUserId);
3980
3981
        if (!isset($_SESSION['filled_surveys'])) {
3982
            return false;
3983
        }
3984
3985
        if (!is_array($_SESSION['filled_surveys'])) {
3986
            return false;
3987
        }
3988
3989
        foreach ($_SESSION['filled_surveys'] as $flag) {
3990
            if ($flagToCheck != $flag) {
3991
                continue;
3992
            }
3993
3994
            return true;
3995
        }
3996
3997
        return false;
3998
    }
3999
4000
    /**
4001
     * Check if the current survey has answers.
4002
     *
4003
     * @param int $surveyId
4004
     *
4005
     * @return bool return true if the survey has answers, false otherwise
4006
     */
4007
    public static function checkIfSurveyHasAnswers(int $surveyId): bool
4008
    {
4009
        $tableSurveyAnswer = Database::get_course_table(TABLE_SURVEY_ANSWER);
4010
4011
        if (empty($surveyId)) {
4012
            return false;
4013
        }
4014
4015
        $sql = "SELECT * FROM $tableSurveyAnswer
4016
                WHERE
4017
                    survey_id = '".$surveyId."'
4018
                ORDER BY iid, user ASC";
4019
        $result = Database::query($sql);
4020
        $response = Database::affected_rows($result);
4021
4022
        return $response > 0;
4023
    }
4024
4025
    /**
4026
     * @param int $surveyId
4027
     * @param int $courseId
4028
     * @param int $sessionId
4029
     *
4030
     * @return array
4031
     */
4032
    public static function getSentInvitations($surveyId, $courseId, $sessionId = 0)
4033
    {
4034
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4035
        $tblSurveyInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
4036
4037
        $sessionCondition = api_get_session_condition($sessionId);
4038
        $surveyId = (int) $surveyId;
4039
        $courseId = (int) $courseId;
4040
4041
        $sql = "SELECT survey_invitation.*, user.firstname, user.lastname, user.email
4042
                FROM $tblSurveyInvitation survey_invitation
4043
                LEFT JOIN $tblUser user
4044
                ON (survey_invitation.user_id = user.id AND survey_invitation.c_id = $courseId)
4045
                WHERE
4046
                    survey_invitation.survey_id = $surveyId AND
4047
                    survey_invitation.c_id = $courseId
4048
                    $sessionCondition";
4049
4050
        $query = Database::query($sql);
4051
4052
        return Database::store_result($query);
4053
    }
4054
4055
    /**
4056
     * @param string $code      invitation code
4057
     * @param int    $sessionId
4058
     *
4059
     * @return string
4060
     */
4061
    public static function generateFillSurveyLink(CSurvey $survey, $invitationCode, Course $course, $sessionId = 0)
4062
    {
4063
        $invitationCode = Security::remove_XSS($invitationCode);
4064
        $sessionId = (int) $sessionId;
4065
4066
        $params = [
4067
            'iid' => $survey->getIid(),
4068
            'invitationcode' => $invitationCode,
4069
            'cid' => $course->getId(),
4070
            'course' => $course->getCode(),
4071
            'sid' => $sessionId,
4072
            'language' => $course->getCourseLanguage(),
4073
        ];
4074
4075
        return api_get_path(WEB_CODE_PATH).'survey/fillsurvey.php?'.http_build_query($params);
4076
    }
4077
}
4078