Passed
Push — master ( 20f08f...fae2d8 )
by Yannick
19:58 queued 11:53
created

SurveyUtil::displayUserReportForm()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 37
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 24
nc 7
nop 2
dl 0
loc 37
rs 8.9137
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, $course_id, $lpItemId = 0): void
82
    {
83
        $sessionId = api_get_session_id();
84
        $course_id = intval($course_id);
85
        // table definition
86
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
87
88
        $lpItemCondition = '';
89
        if (!empty($lpItemId)) {
90
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
91
        }
92
        $sessionCondition = '';
93
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
94
            $sessionCondition = api_get_session_condition($sessionId);
95
        }
96
97
        $sql = "DELETE FROM $table
98
				WHERE
99
                    user = '".Database::escape_string($user)."' AND
100
                    survey_id = '".intval($survey_id)."' AND
101
                    question_id = '".intval($question_id)."'
102
                    $sessionCondition
103
                    $lpItemCondition";
104
        Database::query($sql);
105
    }
106
107
    public static function saveAnswer(
108
        $user,
109
        CSurvey $survey,
110
        CSurveyQuestion $question,
111
        $optionId,
112
        $optionValue,
113
        $otherOption = '',
114
        $lpItemId = 0
115
    ): bool {
116
117
        // Make the survey anonymous
118
        if (1 == $survey->getAnonymous()) {
119
            $surveyUser = Session::read('surveyuser');
120
            if (empty($surveyUser)) {
121
                $user = md5($user.time());
122
                Session::write('surveyuser', $user);
123
            } else {
124
                $user = Session::read('surveyuser');
125
            }
126
        }
127
128
        if (!empty($otherOption)) {
129
            $optionId = $optionId.'@:@'.$otherOption;
130
        }
131
132
        $sessionId = api_get_session_id();
133
        $answer = new CSurveyAnswer();
134
        $answer
135
            ->setUser($user)
136
            ->setSurvey($survey)
137
            ->setQuestion($question)
138
            ->setOptionId($optionId)
139
            ->setValue((int) $optionValue)
140
            ->setLpItemId((int) $lpItemId)
141
            ->setSessionId($sessionId ?: null)
142
        ;
143
144
        $em = Database::getManager();
145
        $em->persist($answer);
146
        $em->flush();
147
148
        $insertId = $answer->getIid();
149
        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...
150
            return true;
151
        }
152
153
        return false;
154
    }
155
156
    /**
157
     * This function checks the parameters that are used in this page.
158
     *
159
     * @return string $people_filled The header, an error and the footer if any parameter fails, else it returns true
160
     *
161
     * @author Patrick Cool <[email protected]>, Ghent University
162
     *
163
     * @version February 2007
164
     */
165
    public static function check_parameters($people_filled)
166
    {
167
        $error = false;
168
169
        // Getting the survey data
170
        $survey_data = SurveyManager::get_survey($_GET['survey_id']);
171
172
        // $_GET['survey_id'] has to be numeric
173
        if (!is_numeric($_GET['survey_id'])) {
174
            $error = get_lang('Unknown survey id');
175
        }
176
177
        // $_GET['action']
178
        $allowed_actions = [
179
            'overview',
180
            'questionreport',
181
            'userreport',
182
            'comparativereport',
183
            'completereport',
184
            'deleteuserreport',
185
        ];
186
        if (isset($_GET['action']) && !in_array($_GET['action'], $allowed_actions)) {
187
            $error = get_lang('Action not allowed');
188
        }
189
190
        // User report
191
        if (isset($_GET['action']) && 'userreport' == $_GET['action']) {
192
            if (0 == $survey_data['anonymous']) {
193
                foreach ($people_filled as $key => &$value) {
194
                    $people_filled_userids[] = $value['invited_user'];
195
                }
196
            } else {
197
                $people_filled_userids = $people_filled;
198
            }
199
200
            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...
201
                $error = get_lang('Unknow user');
202
            }
203
        }
204
205
        // Question report
206
        if (isset($_GET['action']) && 'questionreport' == $_GET['action']) {
207
            if (isset($_GET['question']) && !is_numeric($_GET['question'])) {
208
                $error = get_lang('Unknown question');
209
            }
210
        }
211
212
        if ($error) {
213
            $tool_name = get_lang('Reporting');
214
            Display::addFlash(
215
                Display::return_message(
216
                    get_lang('Error').': '.$error,
217
                    'error',
218
                    false
219
                )
220
            );
221
            Display::display_header($tool_name);
222
            Display::display_footer();
223
            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...
224
        }
225
226
        return true;
227
    }
228
229
    public static function handleReportingActions(CSurvey $survey, array $people_filled = [])
230
    {
231
        $action = $_GET['action'] ?? '';
232
233
        switch ($action) {
234
            case 'questionreport':
235
                self::display_question_report($survey);
236
                break;
237
            case 'userreport':
238
                self::displayUserReport($survey, $people_filled);
239
                break;
240
            case 'comparativereport':
241
                self::display_comparative_report();
242
                break;
243
            case 'completereport':
244
                $surveysAnswered = SurveyManager::getInvitationsAnswered($survey->getCode(), api_get_course_int_id(), api_get_session_id());
245
                if (count($surveysAnswered) > 0) {
246
                    foreach ($surveysAnswered as $survey) {
247
                        echo self::displayCompleteReport($survey, 0, true, true, !$survey->getAnonymous(), $survey->getLpItemId());
248
                    }
249
                }
250
                break;
251
            case 'deleteuserreport':
252
                self::delete_user_report($survey->getIid(), $_GET['user']);
253
                break;
254
        }
255
    }
256
257
    /**
258
     * This function deletes the report of an user who wants to retake the survey.
259
     *
260
     * @param int $survey_id
261
     * @param int $user_id
262
     *
263
     * @author Christian Fasanando Flores <[email protected]>
264
     *
265
     * @version November 2008
266
     */
267
    public static function delete_user_report($survey_id, $user_id)
268
    {
269
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
270
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
271
        $table_survey = Database::get_course_table(TABLE_SURVEY);
272
273
        $course_id = api_get_course_int_id();
274
        $survey_id = (int) $survey_id;
275
        $user_id = Database::escape_string($user_id);
276
277
        if (!empty($survey_id) && !empty($user_id)) {
278
279
            $sessionCondition = '';
280
            if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
281
                $sessionId = api_get_session_id();
282
                $sessionCondition = api_get_session_condition($sessionId);
283
            }
284
285
            // delete data from survey_answer by user_id and survey_id
286
            $sql = "DELETE FROM $table_survey_answer
287
			        WHERE c_id = $course_id AND survey_id = '".$survey_id."' AND user = '".$user_id."' $sessionCondition";
288
            Database::query($sql);
289
            // update field answered from survey_invitation by user_id and survey_id
290
            $sql = "UPDATE $table_survey_invitation SET answered = '0'
291
			        WHERE
292
			            c_id = $course_id AND
293
			            survey_id = (
294
                            SELECT iid FROM $table_survey
295
                            WHERE
296
                                iid = '".$survey_id."'
297
                        ) AND
298
			            user_id = '".$user_id."'  $sessionCondition";
299
            $result = Database::query($sql);
300
        }
301
302
        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...
303
            $message = get_lang('The user\'s answers to the survey have been succesfully removed.').'<br />
304
					<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
305
                .$survey_id.'">'.
306
                get_lang('Go back').'</a>';
307
            echo Display::return_message($message, 'confirmation', false);
308
        }
309
    }
310
311
    /**
312
     * @return string
313
     */
314
    public static function displayUserReportForm(CSurvey $survey, array $people_filled = [])
315
    {
316
        $surveyId = $survey->getIid();
317
        // Step 1: selection of the user
318
        echo "<script>
319
        function jumpMenu(targ,selObj,restore) {
320
            eval(targ+\".location='\"+selObj.options[selObj.selectedIndex].value+\"'\");
321
            if (restore) selObj.selectedIndex=0;
322
        }
323
		</script>";
324
        echo get_lang('Select user who filled the survey').'<br />';
325
        echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
326
        echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
327
            .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
328
            .get_lang('User').'</option>';
329
330
        foreach ($people_filled as $key => &$person) {
331
            if (0 == $survey->getAnonymous()) {
332
                $name = $person['user_info']['complete_name_with_username'];
333
                $id = $person['user_id'];
334
                if ('' == $id) {
335
                    $id = $person['invited_user'];
336
                    $name = $person['invited_user'];
337
                }
338
            } else {
339
                $name = get_lang('Anonymous').' '.($key + 1);
340
                $id = $person;
341
            }
342
            echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
343
                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&user='
344
                .Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
345
            if (isset($_GET['user']) && $_GET['user'] == $id) {
346
                echo 'selected="selected"';
347
            }
348
            echo '>'.$name.'</option>';
349
        }
350
        echo '</select>';
351
    }
352
353
    /**
354
     * @param int   $userId
355
     * @param array $survey_data
356
     * @param bool  $addMessage
357
     */
358
    public static function displayUserReportAnswers($userId, CSurvey $survey, $addMessage = true)
359
    {
360
        // Database table definitions
361
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
362
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
363
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
364
        $course_id = api_get_course_int_id();
365
        $surveyId = $survey->getIid();
366
        $userId = Database::escape_string($userId);
367
368
        $content = '';
369
        // Step 2: displaying the survey and the answer of the selected users
370
        if (!empty($userId)) {
371
            if ($addMessage) {
372
                $content .= Display::return_message(
373
                    get_lang('This screen displays an exact copy of the form as it was filled by the user'),
374
                    'normal',
375
                    false
376
                );
377
            }
378
379
            // Getting all the questions and options
380
            $sql = "SELECT
381
			            survey_question.iid question_id,
382
			            survey_question.survey_id,
383
			            survey_question.survey_question,
384
			            survey_question.display,
385
			            survey_question.max_value,
386
			            survey_question.sort,
387
			            survey_question.type,
388
                        survey_question_option.iid question_option_id,
389
                        survey_question_option.option_text,
390
                        survey_question_option.sort as option_sort
391
					FROM $table_survey_question survey_question
392
					LEFT JOIN $table_survey_question_option survey_question_option
393
					ON
394
					    survey_question.iid = survey_question_option.question_id
395
					WHERE
396
					    survey_question NOT LIKE '%{{%' AND
397
					    survey_question.survey_id = '".$surveyId."'
398
					ORDER BY survey_question.sort, survey_question_option.sort ASC";
399
            $result = Database::query($sql);
400
            while ($row = Database::fetch_assoc($result)) {
401
                if ('pagebreak' !== $row['type']) {
402
                    $questions[$row['sort']]['question_id'] = $row['question_id'];
403
                    $questions[$row['sort']]['survey_id'] = $row['survey_id'];
404
                    $questions[$row['sort']]['survey_question'] = $row['survey_question'];
405
                    $questions[$row['sort']]['display'] = $row['display'];
406
                    $questions[$row['sort']]['type'] = $row['type'];
407
                    $questions[$row['sort']]['maximum_score'] = $row['max_value'];
408
                    $questions[$row['sort']]['options'][$row['question_option_id']] = $row['option_text'];
409
                }
410
            }
411
412
            $sessionCondition = '';
413
            if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
414
                $sessionId = api_get_session_id();
415
                $sessionCondition = api_get_session_condition($sessionId);
416
            }
417
418
            // Getting all the answers of the user
419
            $sql = "SELECT * FROM $table_survey_answer
420
			        WHERE
421
                        survey_id = '".$surveyId."' AND
422
                        user = '".$userId."' $sessionCondition";
423
            $result = Database::query($sql);
424
            while ($row = Database::fetch_assoc($result)) {
425
                $answers[$row['question_id']][] = $row['option_id'];
426
                $all_answers[$row['question_id']][] = $row;
427
            }
428
429
            // Displaying all the questions
430
            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...
431
                // If the question type is a scoring then we have to format the answers differently
432
                switch ($question['type']) {
433
                    case 'score':
434
                        $finalAnswer = [];
435
                        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...
436
                            foreach ($all_answers[$question['question_id']] as $key => &$answer_array) {
437
                                $finalAnswer[$answer_array['option_id']] = $answer_array['value'];
438
                            }
439
                        }
440
                        break;
441
                    case 'multipleresponse':
442
                        $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...
443
                        break;
444
                    default:
445
                        $finalAnswer = '';
446
                        if (isset($all_answers[$question['question_id']])) {
447
                            $finalAnswer = $all_answers[$question['question_id']][0]['option_id'];
448
                        }
449
                        break;
450
                }
451
452
                $display = survey_question::createQuestion($question['type']);
453
                $url = api_get_self();
454
                $form = new FormValidator('question', 'post', $url);
455
                $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
456
                $form->addHtml($question['survey_question']);
457
                $display->render($form, $question, $finalAnswer);
458
                $form->addHtml('</div></div>');
459
                $content .= $form->returnForm();
460
            }
461
        }
462
463
        return $content;
464
    }
465
466
    /**
467
     * This function displays the user report which is basically nothing more
468
     * than a one-page display of all the questions
469
     * of the survey that is filled with the answers of the person who filled the survey.
470
     *
471
     * @return string html code of the one-page survey with the answers of the selected user
472
     *
473
     * @author Patrick Cool <[email protected]>, Ghent University
474
     *
475
     * @version February 2007 - Updated March 2008
476
     */
477
    public static function displayUserReport(CSurvey $survey, $people_filled, $addActionBar = true)
478
    {
479
        $surveyId = $survey->getIid();
480
        $reportingUrl = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
481
482
        // Actions bar
483
        if ($addActionBar) {
484
            $actions = '<a href="'.$reportingUrl.'">'.
485
                Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'))
486
                .'</a>';
487
            if (isset($_GET['user'])) {
488
                if (api_is_allowed_to_edit()) {
489
                    // The delete link
490
                    $actions .= '<a
491
                        href="'.$reportingUrl.'&action=deleteuserreport&user='.Security::remove_XSS($_GET['user']).'" >'.
492
                        Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Delete')).'</a>';
493
                }
494
495
                // Export the user report
496
                $actions .= '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
497
                    .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a> ';
498
                $actions .= '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
499
                    .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a> ';
500
                $actions .= '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
501
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
502
                    .Security::remove_XSS($_GET['user']).'">';
503
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
504
                $actions .= '<input type="hidden" name="export_format" value="csv">';
505
                $actions .= '</form>';
506
                $actions .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
507
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
508
                    .Security::remove_XSS($_GET['user']).'">';
509
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
510
                $actions .= '<input type="hidden" name="export_format" value="xls">';
511
                $actions .= '</form>';
512
                $actions .= '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
513
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
514
            }
515
            echo Display::toolbarAction('survey', [$actions]);
516
        }
517
518
        echo self::displayUserReportForm($survey, $people_filled);
519
        if (isset($_GET['user'])) {
520
            echo self::displayUserReportAnswers($_GET['user'], $survey);
521
        }
522
    }
523
524
    /**
525
     * This function displays the report by question.
526
     *
527
     * It displays a table with all the options of the question and the number of users who have answered positively on
528
     * the option. The number of users who answered positive on a given option is expressed in an absolute number, in a
529
     * percentage of the total and graphically using bars By clicking on the absolute number you get a list with the
530
     * persons who have answered this. You can then click on the name of the person and you will then go to the report
531
     * by user where you see all the answers of that user.
532
     *
533
     * @return string html code that displays the report by question
534
     *
535
     * @todo allow switching between horizontal and vertical.
536
     * @todo multiple response: percentage are probably not OK
537
     * @todo the question and option text have to be shortened and should expand when the user clicks on it.
538
     * @todo the pagebreak and comment question types should not be shown => removed from $survey_data before
539
     *
540
     * @author Patrick Cool <[email protected]>, Ghent University
541
     *
542
     * @version February 2007 - Updated March 2008
543
     */
544
    public static function display_question_report(CSurvey $survey)
545
    {
546
        $singlePage = isset($_GET['single_page']) ? (int) $_GET['single_page'] : 0;
547
        // Determining the offset of the sql statement (the n-th question of the survey)
548
        $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question'];
549
        $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0;
550
        $surveyId = $survey->getIid();
551
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
552
        $course_id = api_get_course_int_id();
553
554
        $sessionCondition = '';
555
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
556
            $sessionId = api_get_session_id();
557
            $sessionCondition = api_get_session_condition($sessionId);
558
        }
559
560
        // Database table definitions
561
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
562
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
563
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
564
565
        $actions = '<a
566
            href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'.
567
            Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
568
                '',
569
                ICON_SIZE_MEDIUM
570
            ).'</a>';
571
        $actions .= Display::url(
572
            Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportToPdf')),
573
            'javascript: void(0);',
574
            ['onclick' => 'exportToPdf();']
575
        );
576
577
        echo Display::toolbarAction('survey', [$actions]);
578
579
        $fromUntil = sprintf(
580
            get_lang('FromXUntilY'),
581
            api_get_local_time($survey->getAvailFrom()),
582
            api_get_local_time($survey->getAvailTill())
583
        );
584
        $max = 80;
585
        $data = [
586
            get_lang('SurveyTitle') => cut(strip_tags($survey->getTitle()), $max),
587
            get_lang('SurveySubTitle') => cut(strip_tags($survey->getSubtitle()), $max),
588
            get_lang('Dates') => $fromUntil,
589
            get_lang('SurveyIntroduction') => cut(strip_tags($survey->getIntro()), $max),
590
        ];
591
592
        $table = new HTML_Table(['id' => 'pdf_table', 'class' => 'table']);
593
        $row = 0;
594
        foreach ($data as $label => $item) {
595
            $table->setCellContents($row, 0, $label);
596
            $table->setCellContents($row, 1, $item);
597
            $row++;
598
        }
599
600
        $questions = $survey->getQuestions();
601
        $numberOfQuestions = 0;
602
        foreach ($questions as $question) {
603
            if ('pagebreak' !== $question->getType()) {
604
                $numberOfQuestions++;
605
            }
606
        }
607
608
        $newQuestionList = [];
609
        if ($numberOfQuestions > 0) {
610
            $limitStatement = null;
611
            if (!$singlePage) {
612
                echo '<div id="question_report_questionnumbers" class="pagination">';
613
                if (0 != $currentQuestion) {
614
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
615
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset - 1).'">'
616
                        .get_lang('Previous question').'</a></li>';
617
                }
618
619
                for ($i = 1; $i <= $numberOfQuestions; $i++) {
620
                    if ($offset != $i - 1) {
621
                        echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
622
                            .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($i - 1).'">'.$i.'</a></li>';
623
                    } else {
624
                        echo '<li class="disabled"s><a href="#">'.$i.'</a></li>';
625
                    }
626
                }
627
                if ($currentQuestion < ($numberOfQuestions - 1)) {
628
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
629
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset + 1).'">'
630
                        .get_lang('Next question').'</li></a>';
631
                }
632
                echo '</ul>';
633
                echo '</div>';
634
                $limitStatement = " LIMIT $offset, 1";
635
            }
636
637
            // Getting the question information
638
            /*$sql = "SELECT * FROM $table_survey_question
639
                    WHERE
640
                        survey_id = $surveyId AND
641
                        survey_question NOT LIKE '%{{%' AND
642
                        type <>'pagebreak'
643
                    ORDER BY sort ASC
644
                    $limitStatement";
645
            $result = Database::query($sql);
646
            while ($row = Database::fetch_array($result)) {*/
647
            foreach ($questions as $question) {
648
                if (strpos($question->getSurveyQuestion(), '%{{%') && 'pagebreak' !== $question->getType()) {
649
                    continue;
650
                }
651
                $newQuestionList[$question->getIid()] = $question;
652
            }
653
        }
654
        echo '<div id="question_results">';
655
        /** @var CSurveyQuestion $question */
656
        foreach ($newQuestionList as $question) {
657
            $chartData = [];
658
            $options = [];
659
            $questionId = $question->getIid();
660
661
            echo '<div class="question-item">';
662
            echo '<div class="title-question">';
663
            echo strip_tags($question->getSurveyQuestion());
664
            echo '</div>';
665
            $type = $question->getType();
666
667
            if ('score' === $type) {
668
                /** @todo This function should return the options as this is needed further in the code */
669
                $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...
670
            } elseif ('open' === $type || 'comment' === $type) {
671
                echo '<div class="open-question">';
672
                /** @todo Also get the user who has answered this */
673
                $sql = "SELECT * FROM $table_survey_answer
674
                        WHERE
675
                            survey_id= $surveyId AND
676
                            question_id = $questionId ";
677
                $result = Database::query($sql);
678
                while ($row = Database::fetch_assoc($result)) {
679
                    echo $row['option_id'].'<hr noshade="noshade" size="1" />';
680
                }
681
                echo '</div>';
682
            } else {
683
                // Getting the options ORDER BY sort ASC
684
                $sql = "SELECT * FROM $table_survey_question_option
685
                        WHERE
686
                            survey_id = $surveyId AND
687
                            question_id = $questionId
688
                        ORDER BY sort ASC";
689
                $result = Database::query($sql);
690
                while ($row = Database::fetch_assoc($result)) {
691
                    $options[$row['iid']] = $row;
692
                }
693
                // Getting the answers
694
                $sql = "SELECT *, count(iid) as total
695
                        FROM $table_survey_answer
696
                        WHERE
697
                            survey_id = $surveyId AND
698
                            question_id = $questionId
699
                        GROUP BY option_id, value";
700
                $result = Database::query($sql);
701
                $number_of_answers = [];
702
                $data = [];
703
                while ($row = Database::fetch_assoc($result)) {
704
                    if (!isset($number_of_answers[$row['question_id']])) {
705
                        $number_of_answers[$row['question_id']] = 0;
706
                    }
707
                    $number_of_answers[$row['question_id']] += $row['total'];
708
                    if ('multiplechoiceother' === $type) {
709
                        $parts = ch_multiplechoiceother::decodeOptionValue($row['option_id']);
710
                        $row['option_id'] = $parts[0];
711
                    }
712
                    $data[$row['option_id']] = $row;
713
                }
714
715
                foreach ($options as $option) {
716
                    $optionText = strip_tags($option['option_text']);
717
                    $optionText = html_entity_decode($optionText);
718
                    $votes = 0;
719
                    if (isset($data[$option['iid']]['total'])) {
720
                        $votes = $data[$option['iid']]['total'];
721
                    }
722
                    array_push($chartData, ['option' => $optionText, 'votes' => $votes]);
723
                }
724
                $chartContainerId = 'chartContainer'.$questionId;
725
                echo '<div id="'.$chartContainerId.'" style="text-align:center;">';
726
                echo self::drawChart($chartData, false, $chartContainerId, false);
727
                echo '</div>';
728
729
                // displaying the table: headers
730
                echo '<table class="display-survey table" id="table_'.$chartContainerId.'">';
731
                echo '';
732
                echo '	<tr>';
733
                echo '		<th style="width: 50%">&nbsp;</th>';
734
                echo '		<th style="width: 10%">'.get_lang('AbsoluteTotal').'</th>';
735
                echo '		<th style="width: 10%">'.get_lang('Percentage').'</th>';
736
                echo '		<th style="width: 30%">'.get_lang('VisualRepresentation').'</th>';
737
                echo '	</tr>';
738
739
                // Displaying the table: the content
740
                if (is_array($options)) {
741
                    foreach ($options as $key => &$value) {
742
                        if ('multiplechoiceother' === $type && 'other' === $value['option_text']) {
743
                            $value['option_text'] = get_lang('SurveyOtherAnswer');
744
                        }
745
746
                        $absolute_number = null;
747
                        if (isset($data[$value['iid']])) {
748
                            $absolute_number = $data[$value['iid']]['total'];
749
                        }
750
                        if ('percentage' === $type && empty($absolute_number)) {
751
                            continue;
752
                        }
753
                        $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...
754
                            ? $number_of_answers[$option['question_id']]
755
                            : 0;
756
                        if (0 == $number_of_answers[$option['question_id']]) {
757
                            $answers_number = 0;
758
                        } else {
759
                            $answers_number = $absolute_number / $number_of_answers[$option['question_id']] * 100;
760
                        }
761
                        echo '	<tr>';
762
                        echo '<td>'.$value['option_text'].'</td>';
763
                        echo '<td>';
764
                        if (0 != $absolute_number) {
765
                            echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
766
                                .'&survey_id='.$surveyId.'&question='.$offset.'&viewoption='
767
                                .$value['iid'].'">'.$absolute_number.'</a>';
768
                        } else {
769
                            echo '0';
770
                        }
771
772
                        echo '      </td>';
773
                        echo '<td>'.round($answers_number, 2).' %</td>';
774
                        echo '<td>';
775
                        $size = $answers_number * 2;
776
                        if ($size > 0) {
777
                            echo '<div
778
                                    style="border:1px solid #264269; background-color:#aecaf4; height:10px;
779
                                    width:'.$size.'px">
780
                                    &nbsp;
781
                                    </div>';
782
                        } else {
783
                            echo '<div style="text-align: left;">'.get_lang("No data available").'</div>';
784
                        }
785
                        echo ' </td>';
786
                        echo ' </tr>';
787
                    }
788
                }
789
790
                $optionResult = '';
791
                if (isset($option['question_id']) && isset($number_of_answers[$option['question_id']])) {
792
                    if (0 == $number_of_answers[$option['question_id']]) {
793
                        $optionResult = '0';
794
                    } else {
795
                        $optionResult = $number_of_answers[$option['question_id']];
796
                    }
797
                }
798
799
                // displaying the table: footer (totals)
800
                echo '	<tr>
801
                            <td><b>'.get_lang('Total').'</b></td>
802
                            <td><b>'.$optionResult.'</b></td>
803
                            <td>&nbsp;</td>
804
                            <td>&nbsp;</td>
805
                        </tr>
806
                        </table>';
807
            }
808
            echo '</div>';
809
        }
810
        echo '</div>';
811
812
        // Survey information, needed for the PDF export.
813
        echo Display::page_subheader(get_lang('Survey')).'<br />';
814
        $table->display();
815
816
        if (isset($_GET['viewoption'])) {
817
            echo '<div class="answered-people">';
818
            echo '<h4>'.get_lang('People who have chosen this answer').': '
819
                .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 656. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
820
821
            if (is_numeric($_GET['value'])) {
822
                $sql_restriction = "AND value='".Database::escape_string($_GET['value'])."'";
823
            }
824
825
            $sql = "SELECT user FROM $table_survey_answer
826
                    WHERE
827
                        c_id = $course_id AND
828
                        option_id = '".Database::escape_string($_GET['viewoption'])."'
829
                        $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...
830
            $result = Database::query($sql);
831
            echo '<ul>';
832
            while ($row = Database::fetch_assoc($result)) {
833
                $user_info = api_get_user_info($row['user']);
834
                echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
835
                    .$surveyId.'&user='.$row['user'].'">'
836
                    .$user_info['complete_name_with_username']
837
                    .'</a></li>';
838
            }
839
            echo '</ul>';
840
            echo '</div>';
841
        }
842
    }
843
844
    /**
845
     * Display score data about a survey question.
846
     *
847
     * @param    int    The offset of results shown
848
     */
849
    public static function display_question_report_score(CSurvey $survey, CSurveyQuestion $question, $offset)
850
    {
851
        // Database table definitions
852
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
853
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
854
        $surveyId = $survey->getIid();
855
        $questionId = $question->getIid();
856
        $options = $survey->getOptions();
857
858
        $sessionCondition = '';
859
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
860
            $sessionId = api_get_session_id();
861
            $sessionCondition = api_get_session_condition($sessionId);
862
        }
863
864
        foreach ($options as $option) {
865
            $options[$option->getIid()] = $option;
866
        }
867
868
        // Getting the answers
869
        $sql = "SELECT *, count(iid) as total
870
                FROM $table_survey_answer
871
                WHERE
872
                   survey_id= $surveyId AND
873
                   question_id = '".$questionId."'
874
                   $sessionCondition
875
                GROUP BY option_id, value";
876
        $result = Database::query($sql);
877
        $number_of_answers = 0;
878
        while ($row = Database::fetch_array($result)) {
879
            $number_of_answers += $row['total'];
880
            $data[$row['option_id']][$row['value']] = $row;
881
        }
882
883
        $chartData = [];
884
        /** @var CSurveyQuestionOption $option */
885
        foreach ($options as $option) {
886
            $optionId = $option->getIid();
887
            $optionText = strip_tags($option->getOptionText());
888
            $optionText = html_entity_decode($optionText);
889
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
890
                $votes = null;
891
                if (isset($data[$optionId][$i])) {
892
                    $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...
893
                }
894
895
                if (empty($votes)) {
896
                    $votes = '0';
897
                }
898
                array_push(
899
                    $chartData,
900
                    [
901
                        'serie' => $optionText,
902
                        'option' => $i,
903
                        'votes' => $votes,
904
                    ]
905
                );
906
            }
907
        }
908
        echo '<div id="chartContainer" class="col-md-12">';
909
        echo self::drawChart($chartData, true);
910
        echo '</div>';
911
912
        // Displaying the table: headers
913
        echo '<table class="table">';
914
        echo '	<tr>';
915
        echo '		<th>&nbsp;</th>';
916
        echo '		<th>'.get_lang('Score').'</th>';
917
        echo '		<th>'.get_lang('Absolute total').'</th>';
918
        echo '		<th>'.get_lang('Percentage').'</th>';
919
        echo '		<th>'.get_lang('Graphic').'</th>';
920
        echo '	</tr>';
921
        // Displaying the table: the content
922
        foreach ($options as $key => $value) {
923
            $optionId = $value->getIid();
924
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
925
                $absolute_number = null;
926
                if (isset($data[$optionId][$i])) {
927
                    $absolute_number = $data[$optionId][$i]['total'];
928
                }
929
930
                echo '<tr>';
931
                echo '<td>'.$value->getOptionText().'</td>';
932
                echo '<td>'.$i.'</td>';
933
934
                echo '<td><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
935
                    .'&survey_id='.$surveyId.'&question='.Security::remove_XSS($offset)
936
                    .'&viewoption='.$optionId.'&value='.$i.'">'.$absolute_number.'</a></td>';
937
938
                $percentage = 0;
939
                $size = 0;
940
                if (!empty($number_of_answers)) {
941
                    $percentage = round($absolute_number / $number_of_answers * 100, 2);
942
                    $size = ($absolute_number / $number_of_answers * 100 * 2);
943
                }
944
                echo '<td>'.$percentage.' %</td>';
945
                echo '<td>';
946
                if ($size > 0) {
947
                    echo '<div
948
                            style="border:1px solid #264269;
949
                            background-color:#aecaf4;
950
                            height:10px; width:'.$size.'px">
951
                            &nbsp;
952
                        </div>';
953
                }
954
                echo '		</td>';
955
                echo '	</tr>';
956
            }
957
        }
958
        // Displaying the table: footer (totals)
959
        echo '	<tr>';
960
        echo '		<td style="border-top:1px solid black"><b>'.get_lang('Total').'</b></td>';
961
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
962
        echo '		<td style="border-top:1px solid black"><b>'.$number_of_answers.'</b></td>';
963
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
964
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
965
        echo '	</tr>';
966
        echo '</table>';
967
    }
968
969
    /**
970
     * This functions displays the complete reporting.
971
     *
972
     * @param int  $userId
973
     * @param bool $addActionBar
974
     * @param bool $addFilters
975
     * @param bool $addExtraFields
976
     *
977
     * @return string
978
     */
979
    public static function displayCompleteReport(
980
        CSurvey $survey,
981
        $userId = 0,
982
        $addActionBar = true,
983
        $addFilters = true,
984
        $addExtraFields = true,
985
        $lpItemId = 0
986
    ) {
987
        // Database table definitions
988
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
989
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
990
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
991
992
        $surveyId = $survey->getIid();
993
        $course_id = api_get_course_int_id();
994
995
        if (empty($surveyId) || empty($course_id)) {
996
            return '';
997
        }
998
999
        $sessionCondition = '';
1000
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
1001
            $sessionId = api_get_session_id();
1002
            $sessionCondition = api_get_session_condition($sessionId);
1003
        }
1004
        $lpItemCondition = '';
1005
        if (!empty($lpItemId)) {
1006
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
1007
        }
1008
1009
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
1010
        $content = '';
1011
        if (!empty($lpItemId)) {
1012
            $tableLp = Database::get_course_table(TABLE_LP_MAIN);
1013
            $tableLpItem = Database::get_course_table(TABLE_LP_ITEM);
1014
            $sql = "SELECT l.name,
1015
                    li.title
1016
                    FROM $tableLpItem li
1017
                    INNER JOIN $tableLp l
1018
                    ON l.iid = li.lp_id AND
1019
                       l.c_id = li.c_id
1020
                    WHERE li.c_id = $course_id AND
1021
                          li.iid = $lpItemId";
1022
            $rs = Database::query($sql);
1023
            if (Database::num_rows($rs) > 0) {
1024
                $row = Database::fetch_assoc($rs);
1025
                $lpName = $row['name'];
1026
                $lpItemTitle = $row['title'];
1027
                $content .= '<h3>'.$lpName.' : '.$lpItemTitle.'</h3>';
1028
            }
1029
        }
1030
1031
        if ($addActionBar) {
1032
            $actions = '<a
1033
                href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
1034
                .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
1035
                    [],
1036
                    ICON_SIZE_MEDIUM
1037
                )
1038
                .'</a>';
1039
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
1040
                .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a>';
1041
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
1042
                .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a>';
1043
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1c.submit();">'
1044
                .Display::getMdiIcon(ActionIcon::EXPORT_ARCHIVE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportAsCompactCSV')).'</a>';
1045
1046
            $content .= Display::toolbarAction('survey', [$actions]);
1047
1048
            // The form
1049
            $content .= '<form
1050
                id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
1051
                .$surveyId.'&'.api_get_cidreq().'">';
1052
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1053
            $content .= '<input type="hidden" name="export_format" value="csv">';
1054
            $content .= '</form>';
1055
            $content .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self(
1056
                ).'?action='.$action.'&survey_id='
1057
                .$surveyId.'&'.api_get_cidreq().'">';
1058
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1059
            $content .= '<input type="hidden" name="export_format" value="xls">';
1060
            $content .= '</form>';
1061
            $content .= '<form id="form1c" name="form1c" method="post" action="'.api_get_self(
1062
                ).'?action='.$action.'&survey_id='
1063
                .$surveyId.'&'.api_get_cidreq().'">';
1064
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1065
            $content .= '<input type="hidden" name="export_format" value="csv-compact">';
1066
            $content .= '</form>';
1067
        }
1068
1069
        $content .= '<form
1070
            id="form2"
1071
            name="form2"
1072
            method="post"
1073
            action="'.api_get_self().'?action='.$action.'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
1074
        $content .= '<br /><table class="table table-hover table-striped data_table" border="1">';
1075
        // Getting the number of options per question
1076
        $content .= '<tr>';
1077
        $content .= '<th>';
1078
1079
        if ($addFilters) {
1080
            if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1081
                (isset($_POST['export_report']) && $_POST['export_report'])
1082
            ) {
1083
                $content .= '<button class="cancel"
1084
                                type="submit"
1085
                                name="reset_question_filter" value="'.get_lang('Reset filter').'">'.
1086
                                get_lang('Reset filter').'</button>';
1087
            }
1088
            $content .= '<button
1089
                            class = "save"
1090
                            type="submit" name="submit_question_filter" value="'.get_lang('Filter').'">'.
1091
                            get_lang('Filter').'</button>';
1092
            $content .= '</th>';
1093
        }
1094
1095
        $display_extra_user_fields = false;
1096
        if ($addExtraFields) {
1097
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1098
                    isset($_POST['export_report']) && $_POST['export_report']) ||
1099
                !empty($_POST['fields_filter'])
1100
            ) {
1101
                // Show user fields section with a big th colspan that spans over all fields
1102
                $extra_user_fields = UserManager::get_extra_fields(
1103
                    0,
1104
                    0,
1105
                    5,
1106
                    'ASC',
1107
                    false,
1108
                    true
1109
                );
1110
                $num = count($extra_user_fields);
1111
                if ($num > 0) {
1112
                    $content .= '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
1113
                    $content .= '<label>';
1114
                    if ($addFilters) {
1115
                        $content .= '<input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
1116
                    }
1117
                    $content .= get_lang('Profile attributes');
1118
                    $content .= '</label>';
1119
                    $content .= '</th>';
1120
                    $display_extra_user_fields = true;
1121
                }
1122
            }
1123
        }
1124
1125
        $sql = "SELECT
1126
                  q.iid question_id,
1127
                  q.type,
1128
                  q.survey_question,
1129
                  count(o.iid) as number_of_options
1130
				FROM $table_survey_question q
1131
				LEFT JOIN $table_survey_question_option o
1132
				ON q.iid = o.question_id
1133
				WHERE
1134
				    survey_question NOT LIKE '%{{%' AND
1135
				    q.survey_id = '".$surveyId."'
1136
				GROUP BY q.iid
1137
				ORDER BY q.sort ASC";
1138
        $result = Database::query($sql);
1139
        $questions = [];
1140
        while ($row = Database::fetch_array($result)) {
1141
            // We show the questions if
1142
            // 1. there is no question filter and the export button has not been clicked
1143
            // 2. there is a quesiton filter but the question is selected for display
1144
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1145
                (is_array($_POST['questions_filter']) &&
1146
                in_array($row['question_id'], $_POST['questions_filter']))
1147
            ) {
1148
                // We do not show comment and pagebreak question types
1149
                if ('pagebreak' !== $row['type']) {
1150
                    $content .= ' <th';
1151
                    if ($row['number_of_options'] > 0 && 'percentage' !== $row['type']) {
1152
                        $content .= ' colspan="'.$row['number_of_options'].'"';
1153
                    }
1154
                    $content .= '>';
1155
                    $content .= '<label>';
1156
                    if ($addFilters) {
1157
                        $content .= '<input
1158
                                type="checkbox"
1159
                                name="questions_filter[]" value="'.$row['question_id'].'" checked="checked"/>';
1160
                    }
1161
                    $content .= $row['survey_question'];
1162
                    $content .= '</label>';
1163
                    $content .= '</th>';
1164
                }
1165
                // No column at all if it's not a question
1166
            }
1167
            $questions[$row['question_id']] = $row;
1168
        }
1169
        $content .= '	</tr>';
1170
1171
        // Getting all the questions and options
1172
        $content .= '	<tr>';
1173
        $content .= '		<th>&nbsp;</th>'; // the user column
1174
1175
        if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1176
            isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter'])
1177
        ) {
1178
            if ($addExtraFields) {
1179
                // show the fields names for user fields
1180
                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...
1181
                    $content .= '<th>'.$field[3].'</th>';
1182
                }
1183
            }
1184
        }
1185
1186
        // cells with option (none for open question)
1187
        $sql = "SELECT
1188
                    sq.iid question_id,
1189
                    sq.survey_id,
1190
                    sq.survey_question,
1191
                    sq.display,
1192
                    sq.sort,
1193
                    sq.type,
1194
                    sqo.iid question_option_id,
1195
                    sqo.option_text,
1196
                    sqo.sort as option_sort
1197
				FROM $table_survey_question sq
1198
				LEFT JOIN $table_survey_question_option sqo
1199
				ON sq.iid = sqo.question_id
1200
				WHERE
1201
				    survey_question NOT LIKE '%{{%' AND
1202
				    sq.survey_id = $surveyId
1203
				ORDER BY sq.sort ASC, sqo.sort ASC";
1204
        $result = Database::query($sql);
1205
1206
        $display_percentage_header = 1;
1207
        $possible_answers = [];
1208
        // in order to display only once the cell option (and not 100 times)
1209
        while ($row = Database::fetch_array($result)) {
1210
            // We show the options if
1211
            // 1. there is no question filter and the export button has not been clicked
1212
            // 2. there is a question filter but the question is selected for display
1213
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1214
                (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']))
1215
            ) {
1216
                // we do not show comment and pagebreak question types
1217
                if ('open' == $row['type'] || 'comment' == $row['type']) {
1218
                    $content .= '<th>&nbsp;-&nbsp;</th>';
1219
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1220
                    $display_percentage_header = 1;
1221
                } elseif ('percentage' == $row['type'] && $display_percentage_header) {
1222
                    $content .= '<th>&nbsp;%&nbsp;</th>';
1223
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1224
                    $display_percentage_header = 0;
1225
                } elseif ('percentage' == $row['type']) {
1226
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1227
                } elseif ('pagebreak' != $row['type'] && 'percentage' != $row['type']) {
1228
                    $content .= '<th>';
1229
                    $content .= $row['option_text'];
1230
                    $content .= '</th>';
1231
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1232
                    $display_percentage_header = 1;
1233
                }
1234
            }
1235
        }
1236
1237
        $content .= '	</tr>';
1238
1239
        $userCondition = '';
1240
        if (!empty($userId)) {
1241
            $userId = (int) $userId;
1242
            $userCondition = " AND user = $userId ";
1243
        }
1244
1245
        // Getting all the answers of the users
1246
        $old_user = '';
1247
        $answers_of_user = [];
1248
        $sql = "SELECT * FROM $table_survey_answer
1249
                WHERE
1250
                    survey_id = $surveyId
1251
                    $userCondition
1252
                    $sessionCondition
1253
                    $lpItemCondition
1254
                ORDER BY iid, user ASC";
1255
        $result = Database::query($sql);
1256
        $i = 1;
1257
        while ($row = Database::fetch_array($result)) {
1258
            if ($old_user != $row['user'] && '' != $old_user) {
1259
                $userParam = $old_user;
1260
                if (0 != $survey->getAnonymous()) {
1261
                    $userParam = $i;
1262
                    $i++;
1263
                }
1264
                $content .= self::display_complete_report_row(
1265
                    $survey,
1266
                    $possible_answers,
1267
                    $answers_of_user,
1268
                    $userParam,
1269
                    $questions,
1270
                    $display_extra_user_fields
1271
                );
1272
                $answers_of_user = [];
1273
            }
1274
            if (isset($questions[$row['question_id']]) &&
1275
                'open' != $questions[$row['question_id']]['type'] &&
1276
                'comment' != $questions[$row['question_id']]['type']
1277
            ) {
1278
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1279
            } else {
1280
                $answers_of_user[$row['question_id']][0] = $row;
1281
            }
1282
            $old_user = $row['user'];
1283
        }
1284
1285
        $userParam = $old_user;
1286
        if (0 != $survey->getAnonymous()) {
1287
            $userParam = $i;
1288
            $i++;
1289
        }
1290
1291
        $content .= self::display_complete_report_row(
1292
            $survey,
1293
            $possible_answers,
1294
            $answers_of_user,
1295
            $userParam,
1296
            $questions,
1297
            $display_extra_user_fields
1298
        );
1299
1300
        // This is to display the last user
1301
        $content .= '</table>';
1302
        $content .= '</form>';
1303
1304
        return $content;
1305
    }
1306
1307
    /**
1308
     * Return user answers in a row.
1309
     *
1310
     * @return string
1311
     */
1312
    public static function display_complete_report_row(
1313
        CSurvey $survey,
1314
        $possible_options,
1315
        $answers_of_user,
1316
        $user,
1317
        $questions,
1318
        $display_extra_user_fields = false
1319
    ) {
1320
        $user = Security::remove_XSS($user);
1321
        $surveyId = $survey->getIid();
1322
1323
        if (empty($surveyId)) {
1324
            return '';
1325
        }
1326
1327
        $content = '<tr>';
1328
        $url = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
1329
        if (0 == $survey->getAnonymous()) {
1330
            if (0 !== (int) $user) {
1331
                $userInfo = api_get_user_info($user);
1332
                $user_displayed = '-';
1333
                if (!empty($userInfo)) {
1334
                    $user_displayed = $userInfo['complete_name_with_username'];
1335
                }
1336
1337
                $content .= '<th>
1338
                    <a href="'.$url.'&action=userreport&user='.$user.'">'
1339
                        .$user_displayed.'
1340
                    </a>
1341
                    </th>'; // the user column
1342
            } else {
1343
                $content .= '<th>'.$user.'</th>'; // the user column
1344
            }
1345
        } else {
1346
            $content .= '<th>'.get_lang('Anonymous').' '.$user.'</th>';
1347
        }
1348
1349
        if ($display_extra_user_fields) {
1350
            // Show user fields data, if any, for this user
1351
            $user_fields_values = UserManager::get_extra_user_data(
1352
                $user,
1353
                false,
1354
                false,
1355
                false,
1356
                true
1357
            );
1358
            foreach ($user_fields_values as &$value) {
1359
                $content .= '<td align="center">'.$value.'</td>';
1360
            }
1361
        }
1362
1363
        if (is_array($possible_options)) {
1364
            foreach ($possible_options as $question_id => &$possible_option) {
1365
                if ('open' === $questions[$question_id]['type'] || 'comment' === $questions[$question_id]['type']) {
1366
                    $content .= '<td align="center">';
1367
                    if (isset($answers_of_user[$question_id]) && isset($answers_of_user[$question_id]['0'])) {
1368
                        $content .= $answers_of_user[$question_id]['0']['option_id'];
1369
                    }
1370
                    $content .= '</td>';
1371
                } else {
1372
                    foreach ($possible_option as $option_id => $value) {
1373
                        if ('multiplechoiceother' === $questions[$question_id]['type']) {
1374
                            foreach ($answers_of_user[$question_id] as $key => $newValue) {
1375
                                $parts = ch_multiplechoiceother::decodeOptionValue($key);
1376
                                if (isset($parts[0])) {
1377
                                    $data = $answers_of_user[$question_id][$key];
1378
                                    unset($answers_of_user[$question_id][$key]);
1379
                                    $newKey = $parts[0];
1380
                                    $answers_of_user[$question_id][$newKey] = $data;
1381
                                }
1382
                            }
1383
                        }
1384
                        if ('percentage' === $questions[$question_id]['type']) {
1385
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1386
                                $content .= "<td align='center'>";
1387
                                $content .= $answers_of_user[$question_id][$option_id]['value'];
1388
                                $content .= "</td>";
1389
                            }
1390
                        } else {
1391
                            $content .= '<td align="center">';
1392
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1393
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1394
                                    $content .= $answers_of_user[$question_id][$option_id]['value'];
1395
                                } else {
1396
                                    $content .= 'v';
1397
                                }
1398
                            }
1399
                        }
1400
                    }
1401
                }
1402
            }
1403
        }
1404
1405
        $content .= '</tr>';
1406
1407
        return $content;
1408
    }
1409
1410
    /**
1411
     * Quite similar to display_complete_report(), returns an HTML string
1412
     * that can be used in a csv file.
1413
     *
1414
     * @param array $survey_data The basic survey data as initially obtained by SurveyManager::get_survey()
1415
     * @param int   $user_id     The ID of the user asking for the report
1416
     * @param bool  $compact     Whether to present the long (v marks with multiple columns per question) or compact
1417
     *                           (one column per question) answers format
1418
     *
1419
     * @todo consider merging this function with display_complete_report
1420
     *
1421
     * @throws Exception
1422
     *
1423
     * @return string The contents of a csv file
1424
     *
1425
     * @author Patrick Cool <[email protected]>, Ghent University
1426
     *
1427
     * @version February 2007
1428
     */
1429
    public static function export_complete_report($survey_data, $user_id = 0, $compact = false)
1430
    {
1431
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
1432
1433
        if (empty($surveyId)) {
1434
            return false;
1435
        }
1436
1437
        $course = api_get_course_info();
1438
        $course_id = $course['real_id'];
1439
1440
        $sessionCondition = '';
1441
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
1442
            $sessionId = api_get_session_id();
1443
            $sessionCondition = api_get_session_condition($sessionId);
1444
        }
1445
1446
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1447
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1448
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1449
1450
        $translate = false;
1451
        if ('true' === api_get_setting('editor.translate_html')) {
1452
            $translate = true;
1453
        }
1454
1455
        // The first column
1456
        $return = ';';
1457
1458
        // Show extra fields blank space (enough for extra fields on next line)
1459
        $extra_user_fields = UserManager::get_extra_fields(
1460
            0,
1461
            0,
1462
            5,
1463
            'ASC',
1464
            false,
1465
            true
1466
        );
1467
1468
        $num = count($extra_user_fields);
1469
        $return .= str_repeat(';', $num);
1470
1471
        $sql = "SELECT
1472
                    questions.iid,
1473
                    questions.type,
1474
                    questions.survey_question,
1475
                    count(options.iid) as number_of_options
1476
				FROM $table_survey_question questions
1477
                LEFT JOIN $table_survey_question_option options
1478
				ON
1479
				  questions.iid = options.question_id
1480
				WHERE
1481
				    survey_question NOT LIKE '%{{%' AND
1482
				    questions.type <> 'pagebreak' AND
1483
				    questions.survey_id = $surveyId
1484
				GROUP BY questions.iid
1485
				ORDER BY questions.sort ASC";
1486
1487
        $result = Database::query($sql);
1488
        while ($row = Database::fetch_array($result)) {
1489
            if ($translate) {
1490
                $row['survey_question'] = api_get_filtered_multilingual_HTML_string($row['survey_question'], $course['language']);
1491
            }
1492
            // We show the questions if
1493
            // 1. there is no question filter and the export button has not been clicked
1494
            // 2. there is a quesiton filter but the question is selected for display
1495
            if (!(isset($_POST['submit_question_filter'])) ||
1496
                (isset($_POST['submit_question_filter']) &&
1497
                    is_array($_POST['questions_filter']) &&
1498
                    in_array($row['iid'], $_POST['questions_filter']))
1499
            ) {
1500
                if (0 == $row['number_of_options'] || $compact) {
1501
                    $return .= str_replace(
1502
                        "\r\n",
1503
                        '  ',
1504
                        api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1505
                    )
1506
                    .';';
1507
                } else {
1508
                    for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1509
                        $return .= str_replace(
1510
                            "\r\n",
1511
                            '  ',
1512
                            api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1513
                        )
1514
                        .';';
1515
                    }
1516
                }
1517
            }
1518
        }
1519
1520
        $return .= "\n";
1521
        // Getting all the questions and options
1522
        $return .= ';';
1523
        // Show the fields names for user fields
1524
        if (!empty($extra_user_fields)) {
1525
            foreach ($extra_user_fields as &$field) {
1526
                if ($translate) {
1527
                    $field[3] = api_get_filtered_multilingual_HTML_string($field[3], $course['language']);
1528
                }
1529
                $return .= '"'
1530
                    .str_replace(
1531
                        "\r\n",
1532
                        '  ',
1533
                        api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES)
1534
                    )
1535
                    .'";';
1536
            }
1537
        }
1538
1539
        $sql = "SELECT DISTINCT
1540
		            survey_question.iid question_id,
1541
		            survey_question.survey_id,
1542
		            survey_question.survey_question,
1543
		            survey_question.display,
1544
		            survey_question.sort,
1545
		            survey_question.type,
1546
                    survey_question_option.iid question_option_id,
1547
                    survey_question_option.option_text,
1548
                    survey_question_option.sort as option_sort
1549
				FROM $table_survey_question survey_question
1550
				LEFT JOIN $table_survey_question_option survey_question_option
1551
				ON
1552
				    survey_question.iid = survey_question_option.question_id
1553
				WHERE
1554
				    survey_question NOT LIKE '%{{%' AND
1555
				    survey_question.type <> 'pagebreak' AND
1556
				    survey_question.survey_id = $surveyId
1557
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1558
        $result = Database::query($sql);
1559
        $possible_answers = [];
1560
        $possible_answers_type = [];
1561
        while ($row = Database::fetch_array($result)) {
1562
            // We show the options if
1563
            // 1. there is no question filter and the export button has not been clicked
1564
            // 2. there is a question filter but the question is selected for display
1565
            if ($translate) {
1566
                $row['option_text'] = api_get_filtered_multilingual_HTML_string($row['option_text'], $course['language']);
1567
            }
1568
            if (!(isset($_POST['submit_question_filter'])) || (
1569
                is_array($_POST['questions_filter']) &&
1570
                in_array($row['question_id'], $_POST['questions_filter'])
1571
            )
1572
            ) {
1573
                $row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']);
1574
                if (!$compact) {
1575
                    $return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';';
1576
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1577
                } else {
1578
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['option_text'];
1579
                }
1580
                $possible_answers_type[$row['question_id']] = $row['type'];
1581
            }
1582
        }
1583
1584
        $return .= "\n";
1585
1586
        // Getting all the answers of the users
1587
        $old_user = '';
1588
        $answers_of_user = [];
1589
        $sql = "SELECT * FROM $table_survey_answer
1590
		        WHERE
1591
		          survey_id = $surveyId
1592
		          $sessionCondition
1593
		          ";
1594
        if (0 != $user_id) {
1595
            $user_id = (int) $user_id;
1596
            $sql .= " AND user = $user_id ";
1597
        }
1598
        $sql .= ' ORDER BY user ASC ';
1599
1600
        $questionIdList = array_keys($possible_answers_type);
1601
        $open_question_iterator = 1;
1602
        $result = Database::query($sql);
1603
        while ($row = Database::fetch_assoc($result)) {
1604
            if (!in_array($row['question_id'], $questionIdList)) {
1605
                continue;
1606
            }
1607
            if ($old_user != $row['user'] && '' != $old_user) {
1608
                $return .= self::export_complete_report_row(
1609
                    $survey_data,
1610
                    $possible_answers,
1611
                    $answers_of_user,
1612
                    $old_user,
1613
                    true,
1614
                    $compact
1615
                );
1616
                $answers_of_user = [];
1617
            }
1618
1619
            if ('open' === $possible_answers_type[$row['question_id']] ||
1620
                'comment' === $possible_answers_type[$row['question_id']]
1621
            ) {
1622
                $temp_id = 'open'.$open_question_iterator;
1623
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1624
                $open_question_iterator++;
1625
            } else {
1626
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1627
            }
1628
            $old_user = $row['user'];
1629
        }
1630
1631
        // This is to display the last user
1632
        $return .= self::export_complete_report_row(
1633
            $survey_data,
1634
            $possible_answers,
1635
            $answers_of_user,
1636
            $old_user,
1637
            true,
1638
            $compact
1639
        );
1640
1641
        return $return;
1642
    }
1643
1644
    /**
1645
     * Add a line to the csv file.
1646
     *
1647
     * @param array $survey_data               Basic survey data (we're mostly interested in the 'anonymous' index)
1648
     * @param array $possible_options          Possible answers
1649
     * @param array $answers_of_user           User's answers
1650
     * @param mixed $user                      User ID or user details as string - Used as a string in the result
1651
     *                                         string
1652
     * @param bool  $display_extra_user_fields Whether to display user fields or not
1653
     * @param bool  $compact                   Whether to show answers as different column values (true) or one column
1654
     *                                         per option (false, default)
1655
     *
1656
     * @return string One line of the csv file
1657
     *
1658
     * @author Patrick Cool <[email protected]>, Ghent University
1659
     *
1660
     * @version February 2007
1661
     */
1662
    public static function export_complete_report_row(
1663
        CSurvey $survey,
1664
        $possible_options,
1665
        $answers_of_user,
1666
        $user,
1667
        $display_extra_user_fields = false,
1668
        $compact = false
1669
    ) {
1670
        $return = '';
1671
        if (0 == $survey->getAnonymous()) {
1672
            if (0 !== intval($user)) {
1673
                $userInfo = api_get_user_info($user);
1674
                if (!empty($userInfo)) {
1675
                    $user_displayed = $userInfo['complete_name_with_username'];
1676
                } else {
1677
                    $user_displayed = '-';
1678
                }
1679
                $return .= $user_displayed.';';
1680
            } else {
1681
                $return .= $user.';';
1682
            }
1683
        } else {
1684
            $return .= '-;'; // The user column
1685
        }
1686
1687
        if ($display_extra_user_fields) {
1688
            // Show user fields data, if any, for this user
1689
            $user_fields_values = UserManager::get_extra_user_data(
1690
                $user,
1691
                false,
1692
                false,
1693
                false,
1694
                true
1695
            );
1696
            foreach ($user_fields_values as &$value) {
1697
                $return .= '"'.str_replace('"', '""', api_html_entity_decode(strip_tags($value), ENT_QUOTES)).'";';
1698
            }
1699
        }
1700
1701
        if (is_array($possible_options)) {
1702
            foreach ($possible_options as $question_id => $possible_option) {
1703
                if (is_array($possible_option) && count($possible_option) > 0) {
1704
                    foreach ($possible_option as $option_id => &$value) {
1705
                        // For each option of this question, look if it matches the user's answer
1706
                        $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];
1707
                        $key = array_keys($my_answer_of_user);
1708
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
1709
                            // If this is an open type question (type starts by 'open'), take whatever answer is given
1710
                            $return .= '"'.
1711
                                str_replace(
1712
                                    '"',
1713
                                    '""',
1714
                                    api_html_entity_decode(
1715
                                        strip_tags(
1716
                                            $answers_of_user[$question_id][$key[0]]['option_id']
1717
                                        ),
1718
                                        ENT_QUOTES
1719
                                    )
1720
                                ).
1721
                                '";';
1722
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1723
                            //$return .= 'v';
1724
                            if ($compact) {
1725
                                // If we asked for a compact view, show only one column for the question
1726
                                // and fill it with the text of the selected option (i.e. "Yes") instead of an ID
1727
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1728
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1729
                                } else {
1730
                                    $return .= '"'.
1731
                                        str_replace(
1732
                                            '"',
1733
                                            '""',
1734
                                            api_html_entity_decode(
1735
                                                strip_tags(
1736
                                                    $possible_option[$option_id]
1737
                                                ),
1738
                                                ENT_QUOTES
1739
                                            )
1740
                                        ).
1741
                                        '";';
1742
                                }
1743
                            } else {
1744
                                // If we don't want a compact view, show one column per possible option and mark a 'v'
1745
                                // or the defined value in the corresponding column if the user selected it
1746
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1747
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1748
                                } else {
1749
                                    $return .= 'v;';
1750
                                }
1751
                            }
1752
                        } else {
1753
                            if (!$compact) {
1754
                                $return .= ';';
1755
                            }
1756
                        }
1757
                    }
1758
                }
1759
            }
1760
        }
1761
        $return .= "\n";
1762
1763
        return $return;
1764
    }
1765
1766
    public static function export_complete_report_xls(CSurvey $survey, $filename, $user_id = 0, $returnFile = false)
1767
    {
1768
        $course_id = api_get_course_int_id();
1769
        $user_id = (int) $user_id;
1770
        $surveyId = $survey->getIid();
1771
1772
        if (empty($course_id) || empty($surveyId)) {
1773
            return false;
1774
        }
1775
1776
        // Show extra fields blank space (enough for extra fields on next line)
1777
        // Show user fields section with a big th colspan that spans over all fields
1778
        $extra_user_fields = UserManager::get_extra_fields(
1779
            0,
1780
            0,
1781
            5,
1782
            'ASC',
1783
            false,
1784
            true
1785
        );
1786
        $list = [];
1787
        $num = count($extra_user_fields);
1788
        for ($i = 0; $i < $num; $i++) {
1789
            $list[0][] = '';
1790
        }
1791
1792
        $display_extra_user_fields = true;
1793
1794
        // Database table definitions
1795
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1796
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1797
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1798
1799
        // First line (questions)
1800
        $sql = "SELECT
1801
                    questions.question_id,
1802
                    questions.type,
1803
                    questions.survey_question,
1804
                    count(options.iid) as number_of_options
1805
				FROM $table_survey_question questions
1806
				LEFT JOIN $table_survey_question_option options
1807
                ON
1808
                  questions.iid = options.question_id
1809
				WHERE
1810
				    survey_question NOT LIKE '%{{%' AND
1811
				    questions.type <> 'pagebreak' AND
1812
				    questions.survey_id = $surveyId
1813
				GROUP BY questions.question_id
1814
				ORDER BY questions.sort ASC";
1815
        $result = Database::query($sql);
1816
        $line = 1;
1817
        $column = 1;
1818
        while ($row = Database::fetch_array($result)) {
1819
            // We show the questions if
1820
            // 1. there is no question filter and the export button has not been clicked
1821
            // 2. there is a quesiton filter but the question is selected for display
1822
            if (!(isset($_POST['submit_question_filter'])) ||
1823
                (isset($_POST['submit_question_filter']) && is_array($_POST['questions_filter']) &&
1824
                in_array($row['question_id'], $_POST['questions_filter']))
1825
            ) {
1826
                // We do not show comment and pagebreak question types
1827
                if ('pagebreak' !== $row['type']) {
1828
                    if (0 == $row['number_of_options'] && ('open' === $row['type'] || 'comment' === $row['type'])) {
1829
                        $list[$line][$column] = api_html_entity_decode(
1830
                            strip_tags($row['survey_question']),
1831
                            ENT_QUOTES
1832
                        );
1833
                        $column++;
1834
                    } else {
1835
                        for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1836
                            $list[$line][$column] = api_html_entity_decode(
1837
                                strip_tags($row['survey_question']),
1838
                                ENT_QUOTES
1839
                            );
1840
                            $column++;
1841
                        }
1842
                    }
1843
                }
1844
            }
1845
        }
1846
1847
        $line++;
1848
        $column = 1;
1849
        // Show extra field values
1850
        if ($display_extra_user_fields) {
1851
            // Show the fields names for user fields
1852
            foreach ($extra_user_fields as &$field) {
1853
                $list[$line][$column] = api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES);
1854
                $column++;
1855
            }
1856
        }
1857
1858
        // Getting all the questions and options (second line)
1859
        $sql = "SELECT
1860
                    survey_question.iid question_id,
1861
                    survey_question.survey_id,
1862
                    survey_question.survey_question,
1863
                    survey_question.display,
1864
                    survey_question.sort,
1865
                    survey_question.type,
1866
                    survey_question_option.iid question_option_id,
1867
                    survey_question_option.option_text,
1868
                    survey_question_option.sort as option_sort
1869
				FROM $table_survey_question survey_question
1870
				LEFT JOIN $table_survey_question_option survey_question_option
1871
				ON
1872
				    survey_question.iid = survey_question_option.question_id
1873
				WHERE
1874
				    survey_question NOT LIKE '%{{%' AND
1875
				    survey_question.type <> 'pagebreak' AND
1876
				    survey_question.survey_id = $surveyId
1877
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1878
        $result = Database::query($sql);
1879
        $possible_answers = [];
1880
        $possible_answers_type = [];
1881
        while ($row = Database::fetch_array($result)) {
1882
            // We show the options if
1883
            // 1. there is no question filter and the export button has not been clicked
1884
            // 2. there is a quesiton filter but the question is selected for display
1885
            if (!isset($_POST['submit_question_filter']) ||
1886
                (isset($_POST['questions_filter']) && is_array($_POST['questions_filter']) &&
1887
                in_array($row['question_id'], $_POST['questions_filter']))
1888
            ) {
1889
                // We do not show comment and pagebreak question types
1890
                if ('pagebreak' !== $row['type']) {
1891
                    $list[$line][$column] = api_html_entity_decode(
1892
                        strip_tags($row['option_text']),
1893
                        ENT_QUOTES
1894
                    );
1895
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1896
                    $possible_answers_type[$row['question_id']] = $row['type'];
1897
                    $column++;
1898
                }
1899
            }
1900
        }
1901
1902
        // Getting all the answers of the users
1903
        $line++;
1904
        $column = 0;
1905
        $old_user = '';
1906
        $answers_of_user = [];
1907
        $sql = "SELECT * FROM $table_survey_answer
1908
                WHERE c_id = $course_id AND survey_id = $surveyId";
1909
        if (0 != $user_id) {
1910
            $sql .= " AND user='".$user_id."' ";
1911
        }
1912
        $sql .= ' ORDER BY user ASC';
1913
1914
        $open_question_iterator = 1;
1915
        $result = Database::query($sql);
1916
        while ($row = Database::fetch_array($result)) {
1917
            if ($old_user != $row['user'] && '' != $old_user) {
1918
                $return = self::export_complete_report_row_xls(
1919
                    $survey,
1920
                    $possible_answers,
1921
                    $answers_of_user,
1922
                    $old_user,
1923
                    true
1924
                );
1925
                foreach ($return as $elem) {
1926
                    $list[$line][$column] = $elem;
1927
                    $column++;
1928
                }
1929
                $answers_of_user = [];
1930
                $line++;
1931
                $column = 0;
1932
            }
1933
            if ('open' === $possible_answers_type[$row['question_id']] || 'comment' === $possible_answers_type[$row['question_id']]) {
1934
                $temp_id = 'open'.$open_question_iterator;
1935
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1936
                $open_question_iterator++;
1937
            } else {
1938
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1939
            }
1940
            $old_user = $row['user'];
1941
        }
1942
1943
        $return = self::export_complete_report_row_xls(
1944
            $survey,
1945
            $possible_answers,
1946
            $answers_of_user,
1947
            $old_user,
1948
            true
1949
        );
1950
1951
        // this is to display the last user
1952
        if (!empty($return)) {
1953
            foreach ($return as $elem) {
1954
                $list[$line][$column] = $elem;
1955
                $column++;
1956
            }
1957
        }
1958
1959
        Export::arrayToXls($list, $filename);
1960
1961
        return null;
1962
    }
1963
1964
    /**
1965
     * Add a line to the csv file.
1966
     *
1967
     * @param array Possible answers
1968
     * @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...
1969
     * @param mixed User ID or user details as string - Used as a string in the result string
1970
     * @param bool Whether to display user fields or not
1971
     *
1972
     * @return array
1973
     */
1974
    public static function export_complete_report_row_xls(
1975
        CSurvey $survey,
1976
        $possible_options,
1977
        $answers_of_user,
1978
        $user,
1979
        $display_extra_user_fields = false
1980
    ) {
1981
        $return = [];
1982
        if (0 == $survey->getAnonymous()) {
1983
            if (0 !== (int) $user) {
1984
                $userInfo = api_get_user_info($user);
1985
                if ($userInfo) {
1986
                    $user_displayed = $userInfo['complete_name_with_username'];
1987
                } else {
1988
                    $user_displayed = '-';
1989
                }
1990
                $return[] = $user_displayed;
1991
            } else {
1992
                $return[] = $user;
1993
            }
1994
        } else {
1995
            $return[] = '-'; // The user column
1996
        }
1997
1998
        if ($display_extra_user_fields) {
1999
            //show user fields data, if any, for this user
2000
            $user_fields_values = UserManager::get_extra_user_data(
2001
                $user,
2002
                false,
2003
                false,
2004
                false,
2005
                true
2006
            );
2007
            foreach ($user_fields_values as $value) {
2008
                $return[] = api_html_entity_decode(strip_tags($value), ENT_QUOTES);
2009
            }
2010
        }
2011
2012
        if (is_array($possible_options)) {
2013
            foreach ($possible_options as $question_id => &$possible_option) {
2014
                if (is_array($possible_option) && count($possible_option) > 0) {
2015
                    foreach ($possible_option as $option_id => &$value) {
2016
                        $my_answers_of_user = $answers_of_user[$question_id] ?? [];
2017
                        $key = array_keys($my_answers_of_user);
2018
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
2019
                            $return[] = api_html_entity_decode(
2020
                                strip_tags($answers_of_user[$question_id][$key[0]]['option_id']),
2021
                                ENT_QUOTES
2022
                            );
2023
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
2024
                            if (0 != $answers_of_user[$question_id][$option_id]['value']) {
2025
                                $return[] = $answers_of_user[$question_id][$option_id]['value'];
2026
                            } else {
2027
                                $return[] = 'v';
2028
                            }
2029
                        } else {
2030
                            $return[] = '';
2031
                        }
2032
                    }
2033
                }
2034
            }
2035
        }
2036
2037
        return $return;
2038
    }
2039
2040
    /**
2041
     * This function displays the comparative report which
2042
     * allows you to compare two questions
2043
     * A comparative report creates a table where one question
2044
     * is on the x axis and a second question is on the y axis.
2045
     * In the intersection is the number of people who have
2046
     * answered positive on both options.
2047
     *
2048
     * @return string HTML code
2049
     *
2050
     * @author Patrick Cool <[email protected]>, Ghent University
2051
     *
2052
     * @version February 2007
2053
     */
2054
    public static function display_comparative_report()
2055
    {
2056
        // Allowed question types for comparative report
2057
        $allowed_question_types = [
2058
            'yesno',
2059
            'multiplechoice',
2060
            'multipleresponse',
2061
            'dropdown',
2062
            'percentage',
2063
            'score',
2064
        ];
2065
2066
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
2067
2068
        // Getting all the questions
2069
        $questions = SurveyManager::get_questions($surveyId);
2070
2071
        // Actions bar
2072
        $actions = '<a href="'.api_get_path(
2073
                WEB_CODE_PATH
2074
            ).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq()
2075
            .'">'
2076
            .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'))
2077
            .'</a>';
2078
        echo Display::toolbarAction('survey', [$actions]);
2079
2080
        // Displaying an information message that only the questions with predefined answers can be used in a comparative report
2081
        echo Display::return_message(get_lang('Only questions with predefined answers can be used'), 'normal', false);
2082
2083
        $xAxis = isset($_GET['xaxis']) ? Security::remove_XSS($_GET['xaxis']) : '';
2084
        $yAxis = isset($_GET['yaxis']) ? Security::remove_XSS($_GET['yaxis']) : '';
2085
2086
        $url = api_get_self().'?'.api_get_cidreq().'&action='.Security::remove_XSS($_GET['action'])
2087
            .'&survey_id='.$surveyId.'&xaxis='.$xAxis.'&y='.$yAxis;
2088
2089
        $form = new FormValidator('compare', 'get', $url);
2090
        $form->addHidden('action', Security::remove_XSS($_GET['action']));
2091
        $form->addHidden('survey_id', $surveyId);
2092
        $optionsX = ['----'];
2093
        $optionsY = ['----'];
2094
        $defaults = [];
2095
        foreach ($questions as $key => &$question) {
2096
            // Ignored tagged questions
2097
            if ($question) {
2098
                if (false !== strpos($question['question'], '{{')) {
2099
                    $question = null;
2100
                    continue;
2101
                }
2102
            }
2103
            if (is_array($allowed_question_types)) {
2104
                if (in_array($question['type'], $allowed_question_types)) {
2105
                    if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) {
2106
                        $defaults['xaxis'] = $question['question_id'];
2107
                    }
2108
2109
                    if (isset($_GET['yaxis']) && $_GET['yaxis'] == $question['question_id']) {
2110
                        $defaults['yaxis'] = $question['question_id'];
2111
                    }
2112
2113
                    $optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2114
                    $optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2115
                }
2116
            }
2117
        }
2118
2119
        $form->addSelect('xaxis', get_lang('Select the question on the X axis'), $optionsX);
2120
        $form->addSelect('yaxis', get_lang('Select the question on the Y axis'), $optionsY);
2121
2122
        $form->addButtonSearch(get_lang('Compare questions'));
2123
        $form->setDefaults($defaults);
2124
        $form->display();
2125
2126
        // Getting all the information of the x axis
2127
        if (is_numeric($xAxis)) {
2128
            $question_x = SurveyManager::get_question($xAxis);
2129
        }
2130
2131
        // Getting all the information of the y axis
2132
        if (is_numeric($yAxis)) {
2133
            $question_y = SurveyManager::get_question($yAxis);
2134
        }
2135
2136
        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...
2137
            // Getting the answers of the two questions
2138
            $answers_x = self::get_answers_of_question_by_user($surveyId, $xAxis);
2139
            $answers_y = self::get_answers_of_question_by_user($surveyId, $yAxis);
2140
2141
            // Displaying the table
2142
            $tableHtml = '<table border="1" class="table table-hover table-striped data_table">';
2143
            $xOptions = [];
2144
            // The header
2145
            $tableHtml .= '<tr>';
2146
            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...
2147
                if (0 == $ii) {
2148
                    $tableHtml .= '<th>&nbsp;</th>';
2149
                } else {
2150
                    if ('score' == $question_x['type']) {
2151
                        for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2152
                            $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'<br />'.$x.'</th>';
2153
                        }
2154
                        $x = '';
2155
                    } else {
2156
                        $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'</th>';
2157
                    }
2158
                    $optionText = strip_tags($question_x['answers'][$ii - 1]);
2159
                    $optionText = html_entity_decode($optionText);
2160
                    array_push($xOptions, trim($optionText));
2161
                }
2162
            }
2163
            $tableHtml .= '</tr>';
2164
            $chartData = [];
2165
            // The main part
2166
            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...
2167
                $currentYQuestion = strip_tags($question_y['answers'][$ij]);
2168
                $currentYQuestion = html_entity_decode($currentYQuestion);
2169
                // The Y axis is a scoring question type so we have more rows than the options (actually options * maximum score)
2170
                if ('score' == $question_y['type']) {
2171
                    for ($y = 1; $y <= $question_y['maximum_score']; $y++) {
2172
                        $tableHtml .= '<tr>';
2173
                        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...
2174
                            if ('score' == $question_x['type']) {
2175
                                for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2176
                                    if (0 == $ii) {
2177
                                        $tableHtml .= '<th>'.$question_y['answers'][($ij)].' '.$y.'</th>';
2178
                                        break;
2179
                                    } else {
2180
                                        $tableHtml .= '<td align="center">';
2181
                                        $votes = self::comparative_check(
2182
                                            $answers_x,
2183
                                            $answers_y,
2184
                                            $question_x['answersid'][($ii - 1)],
2185
                                            $question_y['answersid'][($ij)],
2186
                                            $x,
2187
                                            $y
2188
                                        );
2189
                                        $tableHtml .= $votes;
2190
                                        array_push(
2191
                                            $chartData,
2192
                                            [
2193
                                                'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2194
                                                'option' => $x,
2195
                                                'votes' => $votes,
2196
                                            ]
2197
                                        );
2198
                                        $tableHtml .= '</td>';
2199
                                    }
2200
                                }
2201
                            } else {
2202
                                if (0 == $ii) {
2203
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].' '.$y.'</th>';
2204
                                } else {
2205
                                    $tableHtml .= '<td align="center">';
2206
                                    $votes = self::comparative_check(
2207
                                        $answers_x,
2208
                                        $answers_y,
2209
                                        $question_x['answersid'][($ii - 1)],
2210
                                        $question_y['answersid'][($ij)],
2211
                                        0,
2212
                                        $y
2213
                                    );
2214
                                    $tableHtml .= $votes;
2215
                                    array_push(
2216
                                        $chartData,
2217
                                        [
2218
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2219
                                            'option' => $y,
2220
                                            'votes' => $votes,
2221
                                        ]
2222
                                    );
2223
                                    $tableHtml .= '</td>';
2224
                                }
2225
                            }
2226
                        }
2227
                        $tableHtml .= '</tr>';
2228
                    }
2229
                } else {
2230
                    // The Y axis is NOT a score question type so the number of rows = the number of options
2231
                    $tableHtml .= '<tr>';
2232
                    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...
2233
                        if ('score' == $question_x['type']) {
2234
                            for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2235
                                if (0 == $ii) {
2236
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].'</th>';
2237
                                    break;
2238
                                } else {
2239
                                    $tableHtml .= '<td align="center">';
2240
                                    $votes = self::comparative_check(
2241
                                        $answers_x,
2242
                                        $answers_y,
2243
                                        $question_x['answersid'][($ii - 1)],
2244
                                        $question_y['answersid'][($ij)],
2245
                                        $x,
2246
                                        0
2247
                                    );
2248
                                    $tableHtml .= $votes;
2249
                                    array_push(
2250
                                        $chartData,
2251
                                        [
2252
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2253
                                            'option' => $x,
2254
                                            'votes' => $votes,
2255
                                        ]
2256
                                    );
2257
                                    $tableHtml .= '</td>';
2258
                                }
2259
                            }
2260
                        } else {
2261
                            if (0 == $ii) {
2262
                                $tableHtml .= '<th>'.$question_y['answers'][($ij)].'</th>';
2263
                            } else {
2264
                                $tableHtml .= '<td align="center">';
2265
                                $votes = self::comparative_check(
2266
                                    $answers_x,
2267
                                    $answers_y,
2268
                                    $question_x['answersid'][($ii - 1)],
2269
                                    $question_y['answersid'][($ij)]
2270
                                );
2271
                                $tableHtml .= $votes;
2272
                                array_push(
2273
                                    $chartData,
2274
                                    [
2275
                                        'serie' => $xOptions[$ii - 1],
2276
                                        'option' => $currentYQuestion,
2277
                                        'votes' => $votes,
2278
                                    ]
2279
                                );
2280
                                $tableHtml .= '</td>';
2281
                            }
2282
                        }
2283
                    }
2284
                    $tableHtml .= '</tr>';
2285
                }
2286
            }
2287
            $tableHtml .= '</table>';
2288
            echo '<div id="chartContainer" class="col-md-12">';
2289
            echo self::drawChart($chartData, true);
2290
            echo '</div>';
2291
            echo $tableHtml;
2292
        }
2293
    }
2294
2295
    /**
2296
     * Get all the answers of a question grouped by user.
2297
     *
2298
     * @param int $survey_id   Survey ID
2299
     * @param int $question_id Question ID
2300
     *
2301
     * @return array Array containing all answers of all users, grouped by user
2302
     *
2303
     * @author Patrick Cool <[email protected]>, Ghent University
2304
     *
2305
     * @version February 2007 - Updated March 2008
2306
     */
2307
    public static function get_answers_of_question_by_user($survey_id, $question_id, $lpItemId = 0)
2308
    {
2309
        $course_id = api_get_course_int_id();
2310
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
2311
2312
        $sessionCondition = '';
2313
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
2314
            $sessionId = api_get_session_id();
2315
            $sessionCondition = api_get_session_condition($sessionId);
2316
        }
2317
        $lpItemCondition = '';
2318
        if (!empty($lpItemId)) {
2319
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
2320
        }
2321
2322
        $sql = "SELECT * FROM $table_survey_answer
2323
                WHERE
2324
                  survey_id='".intval($survey_id)."' AND
2325
                  question_id='".intval($question_id)."'
2326
                  $sessionCondition
2327
                  $lpItemCondition
2328
                ORDER BY USER ASC";
2329
        $result = Database::query($sql);
2330
        $return = [];
2331
        while ($row = Database::fetch_array($result)) {
2332
            if (0 == $row['value']) {
2333
                $return[$row['user']][] = $row['option_id'];
2334
            } else {
2335
                $return[$row['user']][] = $row['option_id'].'*'.$row['value'];
2336
            }
2337
        }
2338
2339
        return $return;
2340
    }
2341
2342
    /**
2343
     * Count the number of users who answer positively on both options.
2344
     *
2345
     * @param array All answers of the x axis
2346
     * @param array All answers of the y axis
2347
     * @param int x axis value (= the option_id of the first question)
2348
     * @param int y axis value (= the option_id of the second question)
2349
     *
2350
     * @return int Number of users who have answered positively to both options
2351
     *
2352
     * @author Patrick Cool <[email protected]>, Ghent University
2353
     *
2354
     * @version February 2007
2355
     */
2356
    public static function comparative_check(
2357
        $answers_x,
2358
        $answers_y,
2359
        $option_x,
2360
        $option_y,
2361
        $value_x = 0,
2362
        $value_y = 0
2363
    ) {
2364
        if (0 == $value_x) {
2365
            $check_x = $option_x;
2366
        } else {
2367
            $check_x = $option_x.'*'.$value_x;
2368
        }
2369
        if (0 == $value_y) {
2370
            $check_y = $option_y;
2371
        } else {
2372
            $check_y = $option_y.'*'.$value_y;
2373
        }
2374
2375
        $counter = 0;
2376
        if (is_array($answers_x)) {
2377
            foreach ($answers_x as $user => &$answers) {
2378
                // Check if the user has given $option_x as answer
2379
                if (in_array($check_x, $answers)) {
2380
                    // Check if the user has given $option_y as an answer
2381
                    if (!is_null($answers_y[$user]) &&
2382
                        in_array($check_y, $answers_y[$user])
2383
                    ) {
2384
                        $counter++;
2385
                    }
2386
                }
2387
            }
2388
        }
2389
2390
        return $counter;
2391
    }
2392
2393
    public static function saveInviteMail(CSurvey $survey, $content, $subject, $remind)
2394
    {
2395
        // Database table definition
2396
        if ($remind) {
2397
            $survey->setReminderMail($content);
2398
        } else {
2399
            $survey->setInviteMail($content);
2400
        }
2401
2402
        $survey->setMailSubject($subject);
2403
        $em = Database::getManager();
2404
        $em->persist($survey);
2405
        $em->flush();
2406
    }
2407
2408
    /**
2409
     * This function saves all the invitations of course users
2410
     * and additional users in the database
2411
     * and sends the invitations by email.
2412
     *
2413
     * @param int    $surveyId
2414
     * @param array  $users_array       Users array can be both a list of course uids AND a list of additional email
2415
     *                                  addresses
2416
     * @param string $invitation_title  title of the mail
2417
     * @param string $invitation_text   text of the mail has to contain a **link** string or
2418
     *                                  this will automatically be added to the end
2419
     * @param int    $reminder
2420
     * @param bool   $sendmail
2421
     * @param int    $remindUnAnswered
2422
     * @param bool   $isAdditionalEmail
2423
     * @param bool   $hideLink
2424
     *
2425
     * @author Patrick Cool <[email protected]>, Ghent University
2426
     * @author Julio Montoya - Adding auto-generated link support
2427
     *
2428
     * @version January 2007
2429
     */
2430
    public static function saveInvitations(
2431
        CSurvey $survey,
2432
        $users_array,
2433
        $invitation_title,
2434
        $invitation_text,
2435
        $reminder = 0,
2436
        $sendmail = false,
2437
        $remindUnAnswered = 0,
2438
        $isAdditionalEmail = false,
2439
        $hideLink = false
2440
    ) {
2441
        $surveyId = $survey->getIid();
2442
2443
        if (!is_array($users_array)) {
2444
            return 0;
2445
        }
2446
        $course = api_get_course_entity();
2447
        $session = api_get_session_entity();
2448
        $survey_invitations = self::get_invitations($surveyId);
2449
        $already_invited = self::get_invited_users($survey);
2450
2451
        // Remind unanswered is a special version of remind all reminder
2452
        $exclude_users = [];
2453
        if (1 == $remindUnAnswered) {
2454
            // Remind only unanswered users
2455
            $reminder = 1;
2456
            $exclude_users = SurveyManager::get_people_who_filled_survey($surveyId);
2457
        }
2458
2459
        $counter = 0; // Nr of invitations "sent" (if sendmail option)
2460
        $course_id = api_get_course_int_id();
2461
        $session_id = api_get_session_id();
2462
2463
        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...
2464
            $result = AbstractResource::separateUsersGroups($users_array);
2465
            $groupList = $result['groups'];
2466
            $users_array = $result['users'];
2467
2468
            foreach ($groupList as $groupId) {
2469
                $group = api_get_group_entity($groupId);
2470
                $userGroupList = GroupManager::getStudents($groupId, true);
2471
                $userGroupIdList = array_column($userGroupList, 'user_id');
2472
                $users_array = array_merge($users_array, $userGroupIdList);
2473
2474
                /*$params = [
2475
                    'c_id' => $course_id,
2476
                    'session_id' => $session_id,
2477
                    'group_id' => $groupId,
2478
                    'survey_code' => $survey_data['code'],
2479
                ];*/
2480
2481
                $invitationExists = self::invitationExists(
2482
                    $course_id,
2483
                    $session_id,
2484
                    $groupId,
2485
                    $survey->getIid()
2486
                );
2487
                if (empty($invitationExists)) {
2488
                    self::saveInvitation(
2489
                        '',
2490
                        '',
2491
                        api_get_utc_datetime(time(), false, true),
2492
                        $survey,
2493
                        $course,
2494
                        $session,
2495
                        $group
2496
                    );
2497
                }
2498
            }
2499
        }
2500
2501
        $users_array = array_unique($users_array);
2502
        foreach ($users_array as $value) {
2503
            if (empty($value)) {
2504
                continue;
2505
            }
2506
2507
            // Skip user if reminding only unanswered people
2508
            if (in_array($value, $exclude_users)) {
2509
                continue;
2510
            }
2511
2512
            // Get the unique invitation code if we already have it
2513
            if (1 == $reminder && array_key_exists($value, $survey_invitations)) {
2514
                $invitation_code = $survey_invitations[$value]['invitation_code'];
2515
            } else {
2516
                $invitation_code = md5($value.microtime());
2517
            }
2518
            $new_user = false; // User not already invited
2519
            // Store the invitation if user_id not in $already_invited['course_users'] OR
2520
            // email is not in $already_invited['additional_users']
2521
            $addit_users_array = isset($already_invited['additional_users']) && !empty($already_invited['additional_users'])
2522
                    ? explode(';', $already_invited['additional_users'])
2523
                    : [];
2524
            $my_alredy_invited = $already_invited['course_users'] ?? [];
2525
2526
            $userId = 0;
2527
            if (is_string($value) && filter_var($value, FILTER_VALIDATE_EMAIL)) {
2528
                $userInfo = api_get_user_info_from_email($value);
2529
                if ($userInfo && isset($userInfo['id'])) {
2530
                    $userId = $userInfo['id'];
2531
                }
2532
            } elseif (is_numeric($value)) {
2533
                $userId = $value;
2534
            }
2535
2536
            if ($userId && !in_array($userId, $my_alredy_invited)) {
2537
                $new_user = true;
2538
                if (!array_key_exists($userId, $survey_invitations)) {
2539
                    self::saveInvitation(
2540
                        api_get_user_entity($userId),
2541
                        $invitation_code,
2542
                        api_get_utc_datetime(time(), null, true),
2543
                        $survey,
2544
                        $course,
2545
                        $session
2546
                    );
2547
                }
2548
            }
2549
2550
            // Send the email if checkboxed
2551
            if (($new_user || 1 == $reminder) && $sendmail) {
2552
                // Make a change for absolute url
2553
                if (isset($invitation_text)) {
2554
                    $invitation_text = api_html_entity_decode($invitation_text, ENT_QUOTES);
2555
                    $invitation_text = str_replace('src="../../', 'src="'.api_get_path(WEB_PATH), $invitation_text);
2556
                    $invitation_text = trim(stripslashes($invitation_text));
2557
                }
2558
                self::sendInvitationMail(
2559
                    $survey,
2560
                    $value,
2561
                    $course,
2562
                    $invitation_code,
2563
                    $invitation_title,
2564
                    $invitation_text,
2565
                    $hideLink
2566
                );
2567
                $counter++;
2568
            }
2569
        }
2570
2571
        return $counter; // Number of invitations sent
2572
    }
2573
2574
    public static function saveInvitation(
2575
        User $user,
2576
        $invitationCode,
2577
        $reminderDate,
2578
        CSurvey $survey,
2579
        Course $course,
2580
        SessionEntity $session = null,
2581
        CGroup $group = null
2582
    ): ?CSurveyInvitation {
2583
        $invitation = new CSurveyInvitation();
2584
        $invitation
2585
            ->setUser($user)
2586
            ->setInvitationCode($invitationCode)
2587
            ->setReminderDate($reminderDate)
2588
            ->setSurvey($survey)
2589
            ->setCourse($course)
2590
            ->setSession($session)
2591
            ->setGroup($group)
2592
        ;
2593
2594
        $em = Database::getManager();
2595
        $em->persist($invitation);
2596
        $em->flush();
2597
2598
        return $invitation;
2599
    }
2600
2601
    /**
2602
     * @param int $courseId
2603
     * @param int $sessionId
2604
     * @param int $groupId
2605
     * @param int $surveyId
2606
     *
2607
     * @return int
2608
     */
2609
    public static function invitationExists($courseId, $sessionId, $groupId, $surveyId)
2610
    {
2611
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
2612
        $courseId = (int) $courseId;
2613
        $sessionId = (int) $sessionId;
2614
        $groupId = (int) $groupId;
2615
        $surveyId = (int) $surveyId;
2616
2617
        $sql = "SELECT iid FROM $table
2618
                WHERE
2619
                    c_id = $courseId AND
2620
                    session_id = $sessionId AND
2621
                    group_id = $groupId AND
2622
                    survey_id = $surveyId
2623
                ";
2624
        $result = Database::query($sql);
2625
2626
        return Database::num_rows($result);
2627
    }
2628
2629
    /**
2630
     * Send the invitation by mail.
2631
     *
2632
     * @param int invitedUser - the userId (course user) or emailaddress of additional user
2633
     * @param string $invitation_code - the unique invitation code for the URL
2634
     */
2635
    public static function sendInvitationMail(
2636
        CSurvey $survey,
2637
        $invitedUser,
2638
        Course $course,
2639
        $invitation_code,
2640
        $invitation_title,
2641
        $invitation_text,
2642
        $hideLink = false
2643
    ) {
2644
        $_user = api_get_user_info();
2645
        $sessionId = api_get_session_id();
2646
2647
        // Replacing the **link** part with a valid link for the user
2648
        $link = self::generateFillSurveyLink($survey, $invitation_code, $course, $sessionId);
2649
        if ($hideLink) {
2650
            $full_invitation_text = str_replace('**link**', '', $invitation_text);
2651
        } else {
2652
            $text_link = '<a href="'.$link.'">'.get_lang('Click here to answer the survey')."</a><br />\r\n<br />\r\n"
2653
                .get_lang('or copy paste the following url :')." <br /> \r\n <br /> \r\n ".$link;
2654
2655
            $replace_count = 0;
2656
            $full_invitation_text = api_str_ireplace('**link**', $text_link, $invitation_text, $replace_count);
2657
            if ($replace_count < 1) {
2658
                $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

2658
                $full_invitation_text = /** @scrutinizer ignore-type */ $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
Loading history...
2659
            }
2660
        }
2661
2662
        // Sending the mail
2663
        $sender_name = api_get_person_name($_user['firstName'], $_user['lastName'], null, PERSON_NAME_EMAIL_ADDRESS);
2664
        $sender_email = $_user['mail'];
2665
        $sender_user_id = api_get_user_id();
2666
2667
        $replyto = [];
2668
        if ('noreply' === api_get_setting('survey_email_sender_noreply')) {
2669
            $noreply = api_get_setting('noreply_email_address');
2670
            if (!empty($noreply)) {
2671
                $replyto['Reply-to'] = $noreply;
2672
                $sender_name = $noreply;
2673
                $sender_email = $noreply;
2674
                $sender_user_id = null;
2675
            }
2676
        }
2677
2678
        // Optionally: finding the e-mail of the course user
2679
        if (is_numeric($invitedUser)) {
2680
            MessageManager::send_message(
2681
                $invitedUser,
2682
                $invitation_title,
2683
                $full_invitation_text,
2684
                [],
2685
                [],
2686
                null,
2687
                null,
2688
                null,
2689
                null,
2690
                $sender_user_id,
2691
                true
2692
            );
2693
        } else {
2694
            @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

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