Passed
Push — master ( 8c9b69...801977 )
by Angel Fernando Quiroz
07:02 queued 15s
created

SurveyUtil::checkIfSurveyHasAnswers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 16
rs 10
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_array($result, 'ASSOC')) {
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)
82
    {
83
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
84
        $sql = "DELETE FROM $table
85
				WHERE
86
                    user = '".Database::escape_string($user)."' AND
87
                    survey_id = '".intval($survey_id)."' AND
88
                    question_id = '".intval($question_id)."'";
89
        Database::query($sql);
90
    }
91
92
    public static function saveAnswer(
93
        $user,
94
        CSurvey $survey,
95
        CSurveyQuestion $question,
96
        $optionId,
97
        $optionValue,
98
        $otherOption = ''
99
    ) {
100
        // Make the survey anonymous
101
        if (1 == $survey->getAnonymous()) {
102
            $surveyUser = Session::read('surveyuser');
103
            if (empty($surveyUser)) {
104
                $user = md5($user.time());
105
                Session::write('surveyuser', $user);
106
            } else {
107
                $user = Session::read('surveyuser');
108
            }
109
        }
110
111
        if (!empty($otherOption)) {
112
            $optionId = $optionId.'@:@'.$otherOption;
113
        }
114
115
        $sessionId = api_get_session_id();
116
        $answer = new CSurveyAnswer();
117
        $answer
118
            ->setUser($user)
119
            ->setSurvey($survey)
120
            ->setQuestion($question)
121
            ->setOptionId($optionId)
122
            ->setValue((int) $optionValue)
123
            ->setSessionId($sessionId ?: null)
124
        ;
125
126
        $em = Database::getManager();
127
        $em->persist($answer);
128
        $em->flush();
129
130
        $insertId = $answer->getIid();
131
        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...
132
            return true;
133
        }
134
135
        return false;
136
    }
137
138
    /**
139
     * This function checks the parameters that are used in this page.
140
     *
141
     * @return string $people_filled The header, an error and the footer if any parameter fails, else it returns true
142
     *
143
     * @author Patrick Cool <[email protected]>, Ghent University
144
     *
145
     * @version February 2007
146
     */
147
    public static function check_parameters($people_filled)
148
    {
149
        $error = false;
150
151
        // Getting the survey data
152
        $survey_data = SurveyManager::get_survey($_GET['survey_id']);
153
154
        // $_GET['survey_id'] has to be numeric
155
        if (!is_numeric($_GET['survey_id'])) {
156
            $error = get_lang('Unknown survey id');
157
        }
158
159
        // $_GET['action']
160
        $allowed_actions = [
161
            'overview',
162
            'questionreport',
163
            'userreport',
164
            'comparativereport',
165
            'completereport',
166
            'deleteuserreport',
167
        ];
168
        if (isset($_GET['action']) && !in_array($_GET['action'], $allowed_actions)) {
169
            $error = get_lang('Action not allowed');
170
        }
171
172
        // User report
173
        if (isset($_GET['action']) && 'userreport' == $_GET['action']) {
174
            if (0 == $survey_data['anonymous']) {
175
                foreach ($people_filled as $key => &$value) {
176
                    $people_filled_userids[] = $value['invited_user'];
177
                }
178
            } else {
179
                $people_filled_userids = $people_filled;
180
            }
181
182
            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...
183
                $error = get_lang('Unknow user');
184
            }
185
        }
186
187
        // Question report
188
        if (isset($_GET['action']) && 'questionreport' == $_GET['action']) {
189
            if (isset($_GET['question']) && !is_numeric($_GET['question'])) {
190
                $error = get_lang('Unknown question');
191
            }
192
        }
193
194
        if ($error) {
195
            $tool_name = get_lang('Reporting');
196
            Display::addFlash(
197
                Display::return_message(
198
                    get_lang('Error').': '.$error,
199
                    'error',
200
                    false
201
                )
202
            );
203
            Display::display_header($tool_name);
204
            Display::display_footer();
205
            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...
206
        }
207
208
        return true;
209
    }
210
211
    public static function handleReportingActions(CSurvey $survey, array $people_filled = [])
212
    {
213
        $action = $_GET['action'] ?? '';
214
215
        switch ($action) {
216
            case 'questionreport':
217
                self::display_question_report($survey);
218
                break;
219
            case 'userreport':
220
                self::displayUserReport($survey, $people_filled);
221
                break;
222
            case 'comparativereport':
223
                self::display_comparative_report();
224
                break;
225
            case 'completereport':
226
                echo self::displayCompleteReport($survey);
227
                break;
228
            case 'deleteuserreport':
229
                self::delete_user_report($survey, $_GET['user']);
230
                break;
231
        }
232
    }
233
234
    /**
235
     * This function deletes the report of an user who wants to retake the survey.
236
     *
237
     * @param int $survey_id
238
     * @param int $user_id
239
     *
240
     * @author Christian Fasanando Flores <[email protected]>
241
     *
242
     * @version November 2008
243
     */
244
    public static function delete_user_report($survey_id, $user_id)
245
    {
246
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
247
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
248
        $table_survey = Database::get_course_table(TABLE_SURVEY);
249
250
        $course_id = api_get_course_int_id();
251
        $survey_id = (int) $survey_id;
252
        $user_id = Database::escape_string($user_id);
253
254
        if (!empty($survey_id) && !empty($user_id)) {
255
            // delete data from survey_answer by user_id and survey_id
256
            $sql = "DELETE FROM $table_survey_answer
257
			        WHERE c_id = $course_id AND survey_id = '".$survey_id."' AND user = '".$user_id."'";
258
            Database::query($sql);
259
            // update field answered from survey_invitation by user_id and survey_id
260
            $sql = "UPDATE $table_survey_invitation SET answered = '0'
261
			        WHERE
262
			            c_id = $course_id AND
263
			            survey_id = (
264
                            SELECT iid FROM $table_survey
265
                            WHERE
266
                                iid = '".$survey_id."'
267
                        ) AND
268
			            user_id = '".$user_id."'";
269
            $result = Database::query($sql);
270
        }
271
272
        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...
273
            $message = get_lang('The user\'s answers to the survey have been succesfully removed.').'<br />
274
					<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
275
                .$survey_id.'">'.
276
                get_lang('Go back').'</a>';
277
            echo Display::return_message($message, 'confirmation', false);
278
        }
279
    }
280
281
    /**
282
     * @return string
283
     */
284
    public static function displayUserReportForm(CSurvey $survey, array $people_filled = [])
285
    {
286
        $surveyId = $survey->getIid();
287
        // Step 1: selection of the user
288
        echo "<script>
289
        function jumpMenu(targ,selObj,restore) {
290
            eval(targ+\".location='\"+selObj.options[selObj.selectedIndex].value+\"'\");
291
            if (restore) selObj.selectedIndex=0;
292
        }
293
		</script>";
294
        echo get_lang('Select user who filled the survey').'<br />';
295
        echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
296
        echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
297
            .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($_GET['action']) 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

297
            ./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
Loading history...
298
            .get_lang('User').'</option>';
299
300
        foreach ($people_filled as $key => &$person) {
301
            if (0 == $survey->getAnonymous()) {
302
                $name = $person['user_info']['complete_name_with_username'];
303
                $id = $person['user_id'];
304
                if ('' == $id) {
305
                    $id = $person['invited_user'];
306
                    $name = $person['invited_user'];
307
                }
308
            } else {
309
                $name = get_lang('Anonymous').' '.($key + 1);
310
                $id = $person;
311
            }
312
            echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
313
                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&user='
314
                .Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($id) 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

314
                ./** @scrutinizer ignore-type */ Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
Loading history...
315
            if (isset($_GET['user']) && $_GET['user'] == $id) {
316
                echo 'selected="selected"';
317
            }
318
            echo '>'.$name.'</option>';
319
        }
320
        echo '</select>';
321
    }
322
323
    /**
324
     * @param int   $userId
325
     * @param array $survey_data
326
     * @param bool  $addMessage
327
     */
328
    public static function displayUserReportAnswers($userId, CSurvey $survey, $addMessage = true)
329
    {
330
        // Database table definitions
331
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
332
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
333
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
334
        $course_id = api_get_course_int_id();
335
        $surveyId = $survey->getIid();
336
        $userId = Database::escape_string($userId);
337
338
        $content = '';
339
        // Step 2: displaying the survey and the answer of the selected users
340
        if (!empty($userId)) {
341
            if ($addMessage) {
342
                $content .= Display::return_message(
343
                    get_lang('This screen displays an exact copy of the form as it was filled by the user'),
344
                    'normal',
345
                    false
346
                );
347
            }
348
349
            // Getting all the questions and options
350
            $sql = "SELECT
351
			            survey_question.iid question_id,
352
			            survey_question.survey_id,
353
			            survey_question.survey_question,
354
			            survey_question.display,
355
			            survey_question.max_value,
356
			            survey_question.sort,
357
			            survey_question.type,
358
                        survey_question_option.iid question_option_id,
359
                        survey_question_option.option_text,
360
                        survey_question_option.sort as option_sort
361
					FROM $table_survey_question survey_question
362
					LEFT JOIN $table_survey_question_option survey_question_option
363
					ON
364
					    survey_question.iid = survey_question_option.question_id
365
					WHERE
366
					    survey_question NOT LIKE '%{{%' AND
367
					    survey_question.survey_id = '".$surveyId."'
368
					ORDER BY survey_question.sort, survey_question_option.sort ASC";
369
            $result = Database::query($sql);
370
            while ($row = Database::fetch_array($result, 'ASSOC')) {
371
                if ('pagebreak' !== $row['type']) {
372
                    $questions[$row['sort']]['question_id'] = $row['question_id'];
373
                    $questions[$row['sort']]['survey_id'] = $row['survey_id'];
374
                    $questions[$row['sort']]['survey_question'] = $row['survey_question'];
375
                    $questions[$row['sort']]['display'] = $row['display'];
376
                    $questions[$row['sort']]['type'] = $row['type'];
377
                    $questions[$row['sort']]['maximum_score'] = $row['max_value'];
378
                    $questions[$row['sort']]['options'][$row['question_option_id']] = $row['option_text'];
379
                }
380
            }
381
382
            // Getting all the answers of the user
383
            $sql = "SELECT * FROM $table_survey_answer
384
			        WHERE
385
                        survey_id = '".$surveyId."' AND
386
                        user = '".$userId."'";
387
            $result = Database::query($sql);
388
            while ($row = Database::fetch_array($result, 'ASSOC')) {
389
                $answers[$row['question_id']][] = $row['option_id'];
390
                $all_answers[$row['question_id']][] = $row;
391
            }
392
393
            // Displaying all the questions
394
            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...
395
                // If the question type is a scoring then we have to format the answers differently
396
                switch ($question['type']) {
397
                    case 'score':
398
                        $finalAnswer = [];
399
                        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...
400
                            foreach ($all_answers[$question['question_id']] as $key => &$answer_array) {
401
                                $finalAnswer[$answer_array['option_id']] = $answer_array['value'];
402
                            }
403
                        }
404
                        break;
405
                    case 'multipleresponse':
406
                        $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...
407
                        break;
408
                    default:
409
                        $finalAnswer = '';
410
                        if (isset($all_answers[$question['question_id']])) {
411
                            $finalAnswer = $all_answers[$question['question_id']][0]['option_id'];
412
                        }
413
                        break;
414
                }
415
416
                $display = survey_question::createQuestion($question['type']);
417
                $url = api_get_self();
418
                $form = new FormValidator('question', 'post', $url);
419
                $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
420
                $form->addHtml($question['survey_question']);
421
                $display->render($form, $question, $finalAnswer);
422
                $form->addHtml('</div></div>');
423
                $content .= $form->returnForm();
424
            }
425
        }
426
427
        return $content;
428
    }
429
430
    /**
431
     * This function displays the user report which is basically nothing more
432
     * than a one-page display of all the questions
433
     * of the survey that is filled with the answers of the person who filled the survey.
434
     *
435
     * @return string html code of the one-page survey with the answers of the selected user
436
     *
437
     * @author Patrick Cool <[email protected]>, Ghent University
438
     *
439
     * @version February 2007 - Updated March 2008
440
     */
441
    public static function displayUserReport(CSurvey $survey, $people_filled, $addActionBar = true)
442
    {
443
        $surveyId = $survey->getIid();
444
        $reportingUrl = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
445
446
        // Actions bar
447
        if ($addActionBar) {
448
            $actions = '<a href="'.$reportingUrl.'">'.
449
                Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'))
450
                .'</a>';
451
            if (isset($_GET['user'])) {
452
                if (api_is_allowed_to_edit()) {
453
                    // The delete link
454
                    $actions .= '<a
455
                        href="'.$reportingUrl.'&action=deleteuserreport&user='.Security::remove_XSS($_GET['user']).'" >'.
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($_GET['user']) 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

455
                        href="'.$reportingUrl.'&action=deleteuserreport&user='./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['user']).'" >'.
Loading history...
456
                        Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Delete')).'</a>';
457
                }
458
459
                // Export the user report
460
                $actions .= '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
461
                    .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a> ';
462
                $actions .= '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
463
                    .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a> ';
464
                $actions .= '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
465
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($_GET['action']) 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

465
                    ./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
Loading history...
466
                    .Security::remove_XSS($_GET['user']).'">';
467
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
468
                $actions .= '<input type="hidden" name="export_format" value="csv">';
469
                $actions .= '</form>';
470
                $actions .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
471
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
472
                    .Security::remove_XSS($_GET['user']).'">';
473
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
474
                $actions .= '<input type="hidden" name="export_format" value="xls">';
475
                $actions .= '</form>';
476
                $actions .= '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
477
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
478
            }
479
            echo Display::toolbarAction('survey', [$actions]);
480
        }
481
482
        echo self::displayUserReportForm($survey, $people_filled);
483
        if (isset($_GET['user'])) {
484
            echo self::displayUserReportAnswers($_GET['user'], $survey);
485
        }
486
    }
487
488
    /**
489
     * This function displays the report by question.
490
     *
491
     * It displays a table with all the options of the question and the number of users who have answered positively on
492
     * the option. The number of users who answered positive on a given option is expressed in an absolute number, in a
493
     * percentage of the total and graphically using bars By clicking on the absolute number you get a list with the
494
     * persons who have answered this. You can then click on the name of the person and you will then go to the report
495
     * by user where you see all the answers of that user.
496
     *
497
     * @return string html code that displays the report by question
498
     *
499
     * @todo allow switching between horizontal and vertical.
500
     * @todo multiple response: percentage are probably not OK
501
     * @todo the question and option text have to be shortened and should expand when the user clicks on it.
502
     * @todo the pagebreak and comment question types should not be shown => removed from $survey_data before
503
     *
504
     * @author Patrick Cool <[email protected]>, Ghent University
505
     *
506
     * @version February 2007 - Updated March 2008
507
     */
508
    public static function display_question_report(CSurvey $survey)
509
    {
510
        $singlePage = isset($_GET['single_page']) ? (int) $_GET['single_page'] : 0;
511
        // Determining the offset of the sql statement (the n-th question of the survey)
512
        $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question'];
513
        $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0;
514
        $surveyId = $survey->getIid();
515
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
516
        $course_id = api_get_course_int_id();
517
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
518
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
519
520
        $actions = '<a
521
            href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'.
522
            Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
523
                '',
524
                ICON_SIZE_MEDIUM
525
            ).'</a>';
526
        $actions .= Display::url(
527
            Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportToPdf')),
528
            'javascript: void(0);',
529
            ['onclick' => 'exportToPdf();']
530
        );
531
532
        echo Display::toolbarAction('survey', [$actions]);
533
534
        $fromUntil = sprintf(
535
            get_lang('FromXUntilY'),
536
            api_get_local_time($survey->getAvailFrom()),
537
            api_get_local_time($survey->getAvailTill())
538
        );
539
        $max = 80;
540
        $data = [
541
            get_lang('SurveyTitle') => cut(strip_tags($survey->getTitle()), $max),
542
            get_lang('SurveySubTitle') => cut(strip_tags($survey->getSubtitle()), $max),
543
            get_lang('Dates') => $fromUntil,
544
            get_lang('SurveyIntroduction') => cut(strip_tags($survey->getIntro()), $max),
545
        ];
546
547
        $table = new HTML_Table(['id' => 'pdf_table', 'class' => 'table']);
548
        $row = 0;
549
        foreach ($data as $label => $item) {
550
            $table->setCellContents($row, 0, $label);
551
            $table->setCellContents($row, 1, $item);
552
            $row++;
553
        }
554
555
        $questions = $survey->getQuestions();
556
        $numberOfQuestions = 0;
557
        foreach ($questions as $question) {
558
            if ('pagebreak' !== $question->getType()) {
559
                $numberOfQuestions++;
560
            }
561
        }
562
563
        $newQuestionList = [];
564
        if ($numberOfQuestions > 0) {
565
            $limitStatement = null;
566
            if (!$singlePage) {
567
                echo '<div id="question_report_questionnumbers" class="pagination">';
568
                if (0 != $currentQuestion) {
569
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
0 ignored issues
show
Bug introduced by
Are you sure $action 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

569
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='./** @scrutinizer ignore-type */ $action.'&'
Loading history...
570
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset - 1).'">'
571
                        .get_lang('Previous question').'</a></li>';
572
                }
573
574
                for ($i = 1; $i <= $numberOfQuestions; $i++) {
575
                    if ($offset != $i - 1) {
576
                        echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
577
                            .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($i - 1).'">'.$i.'</a></li>';
578
                    } else {
579
                        echo '<li class="disabled"s><a href="#">'.$i.'</a></li>';
580
                    }
581
                }
582
                if ($currentQuestion < ($numberOfQuestions - 1)) {
583
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
584
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset + 1).'">'
585
                        .get_lang('Next question').'</li></a>';
586
                }
587
                echo '</ul>';
588
                echo '</div>';
589
                $limitStatement = " LIMIT $offset, 1";
590
            }
591
592
            // Getting the question information
593
            /*$sql = "SELECT * FROM $table_survey_question
594
                    WHERE
595
                        survey_id = $surveyId AND
596
                        survey_question NOT LIKE '%{{%' AND
597
                        type <>'pagebreak'
598
                    ORDER BY sort ASC
599
                    $limitStatement";
600
            $result = Database::query($sql);
601
            while ($row = Database::fetch_array($result)) {*/
602
            foreach ($questions as $question) {
603
                if (strpos($question->getSurveyQuestion(), '%{{%') && 'pagebreak' !== $question->getType()) {
604
                    continue;
605
                }
606
                $newQuestionList[$question->getIid()] = $question;
607
            }
608
        }
609
        echo '<div id="question_results">';
610
        /** @var CSurveyQuestion $question */
611
        foreach ($newQuestionList as $question) {
612
            $chartData = [];
613
            $options = [];
614
            $questionId = $question->getIid();
615
616
            echo '<div class="question-item">';
617
            echo '<div class="title-question">';
618
            echo strip_tags($question->getSurveyQuestion());
619
            echo '</div>';
620
            $type = $question->getType();
621
622
            if ('score' === $type) {
623
                /** @todo This function should return the options as this is needed further in the code */
624
                $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...
625
            } elseif ('open' === $type || 'comment' === $type) {
626
                echo '<div class="open-question">';
627
                /** @todo Also get the user who has answered this */
628
                $sql = "SELECT * FROM $table_survey_answer
629
                        WHERE
630
                            survey_id= $surveyId AND
631
                            question_id = $questionId ";
632
                $result = Database::query($sql);
633
                while ($row = Database::fetch_array($result, 'ASSOC')) {
634
                    echo $row['option_id'].'<hr noshade="noshade" size="1" />';
635
                }
636
                echo '</div>';
637
            } else {
638
                // Getting the options ORDER BY sort ASC
639
                $sql = "SELECT * FROM $table_survey_question_option
640
                        WHERE
641
                            survey_id = $surveyId AND
642
                            question_id = $questionId
643
                        ORDER BY sort ASC";
644
                $result = Database::query($sql);
645
                while ($row = Database::fetch_array($result, 'ASSOC')) {
646
                    $options[$row['iid']] = $row;
647
                }
648
                // Getting the answers
649
                $sql = "SELECT *, count(iid) as total
650
                        FROM $table_survey_answer
651
                        WHERE
652
                            survey_id = $surveyId AND
653
                            question_id = $questionId
654
                        GROUP BY option_id, value";
655
                $result = Database::query($sql);
656
                $number_of_answers = [];
657
                $data = [];
658
                while ($row = Database::fetch_array($result, 'ASSOC')) {
659
                    if (!isset($number_of_answers[$row['question_id']])) {
660
                        $number_of_answers[$row['question_id']] = 0;
661
                    }
662
                    $number_of_answers[$row['question_id']] += $row['total'];
663
                    if ('multiplechoiceother' === $type) {
664
                        $parts = ch_multiplechoiceother::decodeOptionValue($row['option_id']);
665
                        $row['option_id'] = $parts[0];
666
                    }
667
                    $data[$row['option_id']] = $row;
668
                }
669
670
                foreach ($options as $option) {
671
                    $optionText = strip_tags($option['option_text']);
672
                    $optionText = html_entity_decode($optionText);
673
                    $votes = 0;
674
                    if (isset($data[$option['iid']]['total'])) {
675
                        $votes = $data[$option['iid']]['total'];
676
                    }
677
                    array_push($chartData, ['option' => $optionText, 'votes' => $votes]);
678
                }
679
                $chartContainerId = 'chartContainer'.$questionId;
680
                echo '<div id="'.$chartContainerId.'" style="text-align:center;">';
681
                echo self::drawChart($chartData, false, $chartContainerId, false);
682
                echo '</div>';
683
684
                // displaying the table: headers
685
                echo '<table class="display-survey table" id="table_'.$chartContainerId.'">';
686
                echo '';
687
                echo '	<tr>';
688
                echo '		<th style="width: 50%">&nbsp;</th>';
689
                echo '		<th style="width: 10%">'.get_lang('AbsoluteTotal').'</th>';
690
                echo '		<th style="width: 10%">'.get_lang('Percentage').'</th>';
691
                echo '		<th style="width: 30%">'.get_lang('VisualRepresentation').'</th>';
692
                echo '	</tr>';
693
694
                // Displaying the table: the content
695
                if (is_array($options)) {
696
                    foreach ($options as $key => &$value) {
697
                        if ('multiplechoiceother' === $type && 'other' === $value['option_text']) {
698
                            $value['option_text'] = get_lang('SurveyOtherAnswer');
699
                        }
700
701
                        $absolute_number = null;
702
                        if (isset($data[$value['iid']])) {
703
                            $absolute_number = $data[$value['iid']]['total'];
704
                        }
705
                        if ('percentage' === $type && empty($absolute_number)) {
706
                            continue;
707
                        }
708
                        $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...
709
                            ? $number_of_answers[$option['question_id']]
710
                            : 0;
711
                        if (0 == $number_of_answers[$option['question_id']]) {
712
                            $answers_number = 0;
713
                        } else {
714
                            $answers_number = $absolute_number / $number_of_answers[$option['question_id']] * 100;
715
                        }
716
                        echo '	<tr>';
717
                        echo '<td>'.$value['option_text'].'</td>';
718
                        echo '<td>';
719
                        if (0 != $absolute_number) {
720
                            echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
721
                                .'&survey_id='.$surveyId.'&question='.$offset.'&viewoption='
722
                                .$value['iid'].'">'.$absolute_number.'</a>';
723
                        } else {
724
                            echo '0';
725
                        }
726
727
                        echo '      </td>';
728
                        echo '<td>'.round($answers_number, 2).' %</td>';
729
                        echo '<td>';
730
                        $size = $answers_number * 2;
731
                        if ($size > 0) {
732
                            echo '<div
733
                                    style="border:1px solid #264269; background-color:#aecaf4; height:10px;
734
                                    width:'.$size.'px">
735
                                    &nbsp;
736
                                    </div>';
737
                        } else {
738
                            echo '<div style="text-align: left;">'.get_lang("No data available").'</div>';
739
                        }
740
                        echo ' </td>';
741
                        echo ' </tr>';
742
                    }
743
                }
744
745
                $optionResult = '';
746
                if (isset($option['question_id']) && isset($number_of_answers[$option['question_id']])) {
747
                    if (0 == $number_of_answers[$option['question_id']]) {
748
                        $optionResult = '0';
749
                    } else {
750
                        $optionResult = $number_of_answers[$option['question_id']];
751
                    }
752
                }
753
754
                // displaying the table: footer (totals)
755
                echo '	<tr>
756
                            <td><b>'.get_lang('Total').'</b></td>
757
                            <td><b>'.$optionResult.'</b></td>
758
                            <td>&nbsp;</td>
759
                            <td>&nbsp;</td>
760
                        </tr>
761
                        </table>';
762
            }
763
            echo '</div>';
764
        }
765
        echo '</div>';
766
767
        // Survey information, needed for the PDF export.
768
        echo Display::page_subheader(get_lang('Survey')).'<br />';
769
        $table->display();
770
771
        if (isset($_GET['viewoption'])) {
772
            echo '<div class="answered-people">';
773
            echo '<h4>'.get_lang('People who have chosen this answer').': '
774
                .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 611. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
775
776
            if (is_numeric($_GET['value'])) {
777
                $sql_restriction = "AND value='".Database::escape_string($_GET['value'])."'";
778
            }
779
780
            $sql = "SELECT user FROM $table_survey_answer
781
                    WHERE
782
                        c_id = $course_id AND
783
                        option_id = '".Database::escape_string($_GET['viewoption'])."'
784
                        $sql_restriction";
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...
785
            $result = Database::query($sql);
786
            echo '<ul>';
787
            while ($row = Database::fetch_array($result, 'ASSOC')) {
788
                $user_info = api_get_user_info($row['user']);
789
                echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
790
                    .$surveyId.'&user='.$row['user'].'">'
791
                    .$user_info['complete_name_with_username']
792
                    .'</a></li>';
793
            }
794
            echo '</ul>';
795
            echo '</div>';
796
        }
797
    }
798
799
    /**
800
     * Display score data about a survey question.
801
     *
802
     * @param    int    The offset of results shown
803
     */
804
    public static function display_question_report_score(CSurvey $survey, CSurveyQuestion $question, $offset)
805
    {
806
        // Database table definitions
807
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
808
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
809
        $surveyId = $survey->getIid();
810
        $questionId = $question->getIid();
811
        $options = $survey->getOptions();
812
        // Getting the options
813
        /*$sql = "SELECT * FROM $table_survey_question_option
814
                WHERE
815
                    survey_id= $surveyId AND
816
                    question_id = '".intval($question['iid'])."'
817
                ORDER BY sort ASC";
818
        $result = Database::query($sql);
819
        while ($row = Database::fetch_array($result)) {*/
820
        foreach ($options as $option) {
821
            $options[$option->getIid()] = $option;
822
        }
823
824
        // Getting the answers
825
        $sql = "SELECT *, count(iid) as total
826
                FROM $table_survey_answer
827
                WHERE
828
                   survey_id= $surveyId AND
829
                   question_id = '".$questionId."'
830
                GROUP BY option_id, value";
831
        $result = Database::query($sql);
832
        $number_of_answers = 0;
833
        while ($row = Database::fetch_array($result)) {
834
            $number_of_answers += $row['total'];
835
            $data[$row['option_id']][$row['value']] = $row;
836
        }
837
838
        $chartData = [];
839
        /** @var CSurveyQuestionOption $option */
840
        foreach ($options as $option) {
841
            $optionId = $option->getIid();
842
            $optionText = strip_tags($option->getOptionText());
843
            $optionText = html_entity_decode($optionText);
844
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
845
                $votes = null;
846
                if (isset($data[$optionId][$i])) {
847
                    $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...
848
                }
849
850
                if (empty($votes)) {
851
                    $votes = '0';
852
                }
853
                array_push(
854
                    $chartData,
855
                    [
856
                        'serie' => $optionText,
857
                        'option' => $i,
858
                        'votes' => $votes,
859
                    ]
860
                );
861
            }
862
        }
863
        echo '<div id="chartContainer" class="col-md-12">';
864
        echo self::drawChart($chartData, true);
865
        echo '</div>';
866
867
        // Displaying the table: headers
868
        echo '<table class="table">';
869
        echo '	<tr>';
870
        echo '		<th>&nbsp;</th>';
871
        echo '		<th>'.get_lang('Score').'</th>';
872
        echo '		<th>'.get_lang('Absolute total').'</th>';
873
        echo '		<th>'.get_lang('Percentage').'</th>';
874
        echo '		<th>'.get_lang('Graphic').'</th>';
875
        echo '	</tr>';
876
        // Displaying the table: the content
877
        foreach ($options as $key => $value) {
878
            $optionId = $value->getIid();
879
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
880
                $absolute_number = null;
881
                if (isset($data[$optionId][$i])) {
882
                    $absolute_number = $data[$optionId][$i]['total'];
883
                }
884
885
                echo '<tr>';
886
                echo '<td>'.$value->getOptionText().'</td>';
887
                echo '<td>'.$i.'</td>';
888
889
                echo '<td><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
0 ignored issues
show
Bug introduced by
Are you sure $action 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

889
                echo '<td><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='./** @scrutinizer ignore-type */ $action
Loading history...
890
                    .'&survey_id='.$surveyId.'&question='.Security::remove_XSS($offset)
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($offset) 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

890
                    .'&survey_id='.$surveyId.'&question='./** @scrutinizer ignore-type */ Security::remove_XSS($offset)
Loading history...
891
                    .'&viewoption='.$optionId.'&value='.$i.'">'.$absolute_number.'</a></td>';
892
893
                $percentage = 0;
894
                $size = 0;
895
                if (!empty($number_of_answers)) {
896
                    $percentage = round($absolute_number / $number_of_answers * 100, 2);
897
                    $size = ($absolute_number / $number_of_answers * 100 * 2);
898
                }
899
                echo '<td>'.$percentage.' %</td>';
900
                echo '<td>';
901
                if ($size > 0) {
902
                    echo '<div
903
                            style="border:1px solid #264269;
904
                            background-color:#aecaf4;
905
                            height:10px; width:'.$size.'px">
906
                            &nbsp;
907
                        </div>';
908
                }
909
                echo '		</td>';
910
                echo '	</tr>';
911
            }
912
        }
913
        // Displaying the table: footer (totals)
914
        echo '	<tr>';
915
        echo '		<td style="border-top:1px solid black"><b>'.get_lang('Total').'</b></td>';
916
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
917
        echo '		<td style="border-top:1px solid black"><b>'.$number_of_answers.'</b></td>';
918
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
919
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
920
        echo '	</tr>';
921
        echo '</table>';
922
    }
923
924
    /**
925
     * This functions displays the complete reporting.
926
     *
927
     * @param int  $userId
928
     * @param bool $addActionBar
929
     * @param bool $addFilters
930
     * @param bool $addExtraFields
931
     *
932
     * @return string
933
     */
934
    public static function displayCompleteReport(
935
        CSurvey $survey,
936
        $userId = 0,
937
        $addActionBar = true,
938
        $addFilters = true,
939
        $addExtraFields = true
940
    ) {
941
        // Database table definitions
942
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
943
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
944
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
945
946
        $surveyId = $survey->getIid();
947
        $course_id = api_get_course_int_id();
948
949
        if (empty($surveyId) || empty($course_id)) {
950
            return '';
951
        }
952
953
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
954
        $content = '';
955
        if ($addActionBar) {
956
            $actions = '<a
957
                href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
958
                .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
959
                    [],
960
                    ICON_SIZE_MEDIUM
961
                )
962
                .'</a>';
963
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
964
                .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a>';
965
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
966
                .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a>';
967
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1c.submit();">'
968
                .Display::getMdiIcon(ActionIcon::EXPORT_ARCHIVE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportAsCompactCSV')).'</a>';
969
970
            $content .= Display::toolbarAction('survey', [$actions]);
971
972
            // The form
973
            $content .= '<form
974
                id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
0 ignored issues
show
Bug introduced by
Are you sure $action 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

974
                id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='./** @scrutinizer ignore-type */ $action.'&survey_id='
Loading history...
975
                .$surveyId.'&'.api_get_cidreq().'">';
976
            $content .= '<input type="hidden" name="export_report" value="export_report">';
977
            $content .= '<input type="hidden" name="export_format" value="csv">';
978
            $content .= '</form>';
979
            $content .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self(
980
                ).'?action='.$action.'&survey_id='
981
                .$surveyId.'&'.api_get_cidreq().'">';
982
            $content .= '<input type="hidden" name="export_report" value="export_report">';
983
            $content .= '<input type="hidden" name="export_format" value="xls">';
984
            $content .= '</form>';
985
            $content .= '<form id="form1c" name="form1c" method="post" action="'.api_get_self(
986
                ).'?action='.$action.'&survey_id='
987
                .$surveyId.'&'.api_get_cidreq().'">';
988
            $content .= '<input type="hidden" name="export_report" value="export_report">';
989
            $content .= '<input type="hidden" name="export_format" value="csv-compact">';
990
            $content .= '</form>';
991
        }
992
993
        $content .= '<form
994
            id="form2"
995
            name="form2"
996
            method="post"
997
            action="'.api_get_self().'?action='.$action.'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
998
        $content .= '<br /><table class="table table-hover table-striped data_table" border="1">';
999
        // Getting the number of options per question
1000
        $content .= '<tr>';
1001
        $content .= '<th>';
1002
1003
        if ($addFilters) {
1004
            if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1005
                (isset($_POST['export_report']) && $_POST['export_report'])
1006
            ) {
1007
                $content .= '<button class="cancel"
1008
                                type="submit"
1009
                                name="reset_question_filter" value="'.get_lang('Reset filter').'">'.
1010
                                get_lang('Reset filter').'</button>';
1011
            }
1012
            $content .= '<button
1013
                            class = "save"
1014
                            type="submit" name="submit_question_filter" value="'.get_lang('Filter').'">'.
1015
                            get_lang('Filter').'</button>';
1016
            $content .= '</th>';
1017
        }
1018
1019
        $display_extra_user_fields = false;
1020
        if ($addExtraFields) {
1021
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1022
                    isset($_POST['export_report']) && $_POST['export_report']) ||
1023
                !empty($_POST['fields_filter'])
1024
            ) {
1025
                // Show user fields section with a big th colspan that spans over all fields
1026
                $extra_user_fields = UserManager::get_extra_fields(
1027
                    0,
1028
                    0,
1029
                    5,
1030
                    'ASC',
1031
                    false,
1032
                    true
1033
                );
1034
                $num = count($extra_user_fields);
1035
                if ($num > 0) {
1036
                    $content .= '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
1037
                    $content .= '<label>';
1038
                    if ($addFilters) {
1039
                        $content .= '<input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
1040
                    }
1041
                    $content .= get_lang('Profile attributes');
1042
                    $content .= '</label>';
1043
                    $content .= '</th>';
1044
                    $display_extra_user_fields = true;
1045
                }
1046
            }
1047
        }
1048
1049
        $sql = "SELECT
1050
                  q.iid question_id,
1051
                  q.type,
1052
                  q.survey_question,
1053
                  count(o.iid) as number_of_options
1054
				FROM $table_survey_question q
1055
				LEFT JOIN $table_survey_question_option o
1056
				ON q.iid = o.question_id
1057
				WHERE
1058
				    survey_question NOT LIKE '%{{%' AND
1059
				    q.survey_id = '".$surveyId."'
1060
				GROUP BY q.iid
1061
				ORDER BY q.sort ASC";
1062
        $result = Database::query($sql);
1063
        $questions = [];
1064
        while ($row = Database::fetch_array($result)) {
1065
            // We show the questions if
1066
            // 1. there is no question filter and the export button has not been clicked
1067
            // 2. there is a quesiton filter but the question is selected for display
1068
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1069
                (is_array($_POST['questions_filter']) &&
1070
                in_array($row['question_id'], $_POST['questions_filter']))
1071
            ) {
1072
                // We do not show comment and pagebreak question types
1073
                if ('pagebreak' !== $row['type']) {
1074
                    $content .= ' <th';
1075
                    if ($row['number_of_options'] > 0 && 'percentage' !== $row['type']) {
1076
                        $content .= ' colspan="'.$row['number_of_options'].'"';
1077
                    }
1078
                    $content .= '>';
1079
                    $content .= '<label>';
1080
                    if ($addFilters) {
1081
                        $content .= '<input
1082
                                type="checkbox"
1083
                                name="questions_filter[]" value="'.$row['question_id'].'" checked="checked"/>';
1084
                    }
1085
                    $content .= $row['survey_question'];
1086
                    $content .= '</label>';
1087
                    $content .= '</th>';
1088
                }
1089
                // No column at all if it's not a question
1090
            }
1091
            $questions[$row['question_id']] = $row;
1092
        }
1093
        $content .= '	</tr>';
1094
1095
        // Getting all the questions and options
1096
        $content .= '	<tr>';
1097
        $content .= '		<th>&nbsp;</th>'; // the user column
1098
1099
        if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1100
            isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter'])
1101
        ) {
1102
            if ($addExtraFields) {
1103
                // show the fields names for user fields
1104
                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...
1105
                    $content .= '<th>'.$field[3].'</th>';
1106
                }
1107
            }
1108
        }
1109
1110
        // cells with option (none for open question)
1111
        $sql = "SELECT
1112
                    sq.iid question_id,
1113
                    sq.survey_id,
1114
                    sq.survey_question,
1115
                    sq.display,
1116
                    sq.sort,
1117
                    sq.type,
1118
                    sqo.iid question_option_id,
1119
                    sqo.option_text,
1120
                    sqo.sort as option_sort
1121
				FROM $table_survey_question sq
1122
				LEFT JOIN $table_survey_question_option sqo
1123
				ON sq.iid = sqo.question_id
1124
				WHERE
1125
				    survey_question NOT LIKE '%{{%' AND
1126
				    sq.survey_id = $surveyId
1127
				ORDER BY sq.sort ASC, sqo.sort ASC";
1128
        $result = Database::query($sql);
1129
1130
        $display_percentage_header = 1;
1131
        $possible_answers = [];
1132
        // in order to display only once the cell option (and not 100 times)
1133
        while ($row = Database::fetch_array($result)) {
1134
            // We show the options if
1135
            // 1. there is no question filter and the export button has not been clicked
1136
            // 2. there is a question filter but the question is selected for display
1137
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1138
                (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']))
1139
            ) {
1140
                // we do not show comment and pagebreak question types
1141
                if ('open' == $row['type'] || 'comment' == $row['type']) {
1142
                    $content .= '<th>&nbsp;-&nbsp;</th>';
1143
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1144
                    $display_percentage_header = 1;
1145
                } elseif ('percentage' == $row['type'] && $display_percentage_header) {
1146
                    $content .= '<th>&nbsp;%&nbsp;</th>';
1147
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1148
                    $display_percentage_header = 0;
1149
                } elseif ('percentage' == $row['type']) {
1150
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1151
                } elseif ('pagebreak' != $row['type'] && 'percentage' != $row['type']) {
1152
                    $content .= '<th>';
1153
                    $content .= $row['option_text'];
1154
                    $content .= '</th>';
1155
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1156
                    $display_percentage_header = 1;
1157
                }
1158
            }
1159
        }
1160
1161
        $content .= '	</tr>';
1162
1163
        $userCondition = '';
1164
        if (!empty($userId)) {
1165
            $userId = (int) $userId;
1166
            $userCondition = " AND user = $userId ";
1167
        }
1168
1169
        // Getting all the answers of the users
1170
        $old_user = '';
1171
        $answers_of_user = [];
1172
        $sql = "SELECT * FROM $table_survey_answer
1173
                WHERE
1174
                    survey_id = $surveyId
1175
                    $userCondition
1176
                ORDER BY iid, user ASC";
1177
        $result = Database::query($sql);
1178
        $i = 1;
1179
        while ($row = Database::fetch_array($result)) {
1180
            if ($old_user != $row['user'] && '' != $old_user) {
1181
                $userParam = $old_user;
1182
                if (0 != $survey->getAnonymous()) {
1183
                    $userParam = $i;
1184
                    $i++;
1185
                }
1186
                $content .= self::display_complete_report_row(
1187
                    $survey,
1188
                    $possible_answers,
1189
                    $answers_of_user,
1190
                    $userParam,
1191
                    $questions,
1192
                    $display_extra_user_fields
1193
                );
1194
                $answers_of_user = [];
1195
            }
1196
            if (isset($questions[$row['question_id']]) &&
1197
                'open' != $questions[$row['question_id']]['type'] &&
1198
                'comment' != $questions[$row['question_id']]['type']
1199
            ) {
1200
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1201
            } else {
1202
                $answers_of_user[$row['question_id']][0] = $row;
1203
            }
1204
            $old_user = $row['user'];
1205
        }
1206
1207
        $userParam = $old_user;
1208
        if (0 != $survey->getAnonymous()) {
1209
            $userParam = $i;
1210
            $i++;
1211
        }
1212
1213
        $content .= self::display_complete_report_row(
1214
            $survey,
1215
            $possible_answers,
1216
            $answers_of_user,
1217
            $userParam,
1218
            $questions,
1219
            $display_extra_user_fields
1220
        );
1221
1222
        // This is to display the last user
1223
        $content .= '</table>';
1224
        $content .= '</form>';
1225
1226
        return $content;
1227
    }
1228
1229
    /**
1230
     * Return user answers in a row.
1231
     *
1232
     * @return string
1233
     */
1234
    public static function display_complete_report_row(
1235
        CSurvey $survey,
1236
        $possible_options,
1237
        $answers_of_user,
1238
        $user,
1239
        $questions,
1240
        $display_extra_user_fields = false
1241
    ) {
1242
        $user = Security::remove_XSS($user);
1243
        $surveyId = $survey->getIid();
1244
1245
        if (empty($surveyId)) {
1246
            return '';
1247
        }
1248
1249
        $content = '<tr>';
1250
        $url = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
1251
        if (0 == $survey->getAnonymous()) {
1252
            if (0 !== (int) $user) {
1253
                $userInfo = api_get_user_info($user);
1254
                $user_displayed = '-';
1255
                if (!empty($userInfo)) {
1256
                    $user_displayed = $userInfo['complete_name_with_username'];
1257
                }
1258
1259
                $content .= '<th>
1260
                    <a href="'.$url.'&action=userreport&user='.$user.'">'
0 ignored issues
show
Bug introduced by
Are you sure $user 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

1260
                    <a href="'.$url.'&action=userreport&user='./** @scrutinizer ignore-type */ $user.'">'
Loading history...
1261
                        .$user_displayed.'
1262
                    </a>
1263
                    </th>'; // the user column
1264
            } else {
1265
                $content .= '<th>'.$user.'</th>'; // the user column
1266
            }
1267
        } else {
1268
            $content .= '<th>'.get_lang('Anonymous').' '.$user.'</th>';
1269
        }
1270
1271
        if ($display_extra_user_fields) {
1272
            // Show user fields data, if any, for this user
1273
            $user_fields_values = UserManager::get_extra_user_data(
1274
                $user,
1275
                false,
1276
                false,
1277
                false,
1278
                true
1279
            );
1280
            foreach ($user_fields_values as &$value) {
1281
                $content .= '<td align="center">'.$value.'</td>';
1282
            }
1283
        }
1284
1285
        if (is_array($possible_options)) {
1286
            foreach ($possible_options as $question_id => &$possible_option) {
1287
                if ('open' === $questions[$question_id]['type'] || 'comment' === $questions[$question_id]['type']) {
1288
                    $content .= '<td align="center">';
1289
                    if (isset($answers_of_user[$question_id]) && isset($answers_of_user[$question_id]['0'])) {
1290
                        $content .= $answers_of_user[$question_id]['0']['option_id'];
1291
                    }
1292
                    $content .= '</td>';
1293
                } else {
1294
                    foreach ($possible_option as $option_id => $value) {
1295
                        if ('multiplechoiceother' === $questions[$question_id]['type']) {
1296
                            foreach ($answers_of_user[$question_id] as $key => $newValue) {
1297
                                $parts = ch_multiplechoiceother::decodeOptionValue($key);
1298
                                if (isset($parts[0])) {
1299
                                    $data = $answers_of_user[$question_id][$key];
1300
                                    unset($answers_of_user[$question_id][$key]);
1301
                                    $newKey = $parts[0];
1302
                                    $answers_of_user[$question_id][$newKey] = $data;
1303
                                }
1304
                            }
1305
                        }
1306
                        if ('percentage' === $questions[$question_id]['type']) {
1307
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1308
                                $content .= "<td align='center'>";
1309
                                $content .= $answers_of_user[$question_id][$option_id]['value'];
1310
                                $content .= "</td>";
1311
                            }
1312
                        } else {
1313
                            $content .= '<td align="center">';
1314
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1315
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1316
                                    $content .= $answers_of_user[$question_id][$option_id]['value'];
1317
                                } else {
1318
                                    $content .= 'v';
1319
                                }
1320
                            }
1321
                        }
1322
                    }
1323
                }
1324
            }
1325
        }
1326
1327
        $content .= '</tr>';
1328
1329
        return $content;
1330
    }
1331
1332
    /**
1333
     * Quite similar to display_complete_report(), returns an HTML string
1334
     * that can be used in a csv file.
1335
     *
1336
     * @param array $survey_data The basic survey data as initially obtained by SurveyManager::get_survey()
1337
     * @param int   $user_id     The ID of the user asking for the report
1338
     * @param bool  $compact     Whether to present the long (v marks with multiple columns per question) or compact
1339
     *                           (one column per question) answers format
1340
     *
1341
     * @todo consider merging this function with display_complete_report
1342
     *
1343
     * @throws Exception
1344
     *
1345
     * @return string The contents of a csv file
1346
     *
1347
     * @author Patrick Cool <[email protected]>, Ghent University
1348
     *
1349
     * @version February 2007
1350
     */
1351
    public static function export_complete_report($survey_data, $user_id = 0, $compact = false)
1352
    {
1353
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
1354
1355
        if (empty($surveyId)) {
1356
            return false;
1357
        }
1358
1359
        $course = api_get_course_info();
1360
        $course_id = $course['real_id'];
1361
1362
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1363
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1364
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1365
1366
        $translate = false;
1367
        if ('true' === api_get_setting('editor.translate_html')) {
1368
            $translate = true;
1369
        }
1370
1371
        // The first column
1372
        $return = ';';
1373
1374
        // Show extra fields blank space (enough for extra fields on next line)
1375
        $extra_user_fields = UserManager::get_extra_fields(
1376
            0,
1377
            0,
1378
            5,
1379
            'ASC',
1380
            false,
1381
            true
1382
        );
1383
1384
        $num = count($extra_user_fields);
1385
        $return .= str_repeat(';', $num);
1386
1387
        $sql = "SELECT
1388
                    questions.iid,
1389
                    questions.type,
1390
                    questions.survey_question,
1391
                    count(options.iid) as number_of_options
1392
				FROM $table_survey_question questions
1393
                LEFT JOIN $table_survey_question_option options
1394
				ON
1395
				  questions.iid = options.question_id
1396
				WHERE
1397
				    survey_question NOT LIKE '%{{%' AND
1398
				    questions.type <> 'pagebreak' AND
1399
				    questions.survey_id = $surveyId
1400
				GROUP BY questions.iid
1401
				ORDER BY questions.sort ASC";
1402
1403
        $result = Database::query($sql);
1404
        while ($row = Database::fetch_array($result)) {
1405
            if ($translate) {
1406
                $row['survey_question'] = api_get_filtered_multilingual_HTML_string($row['survey_question'], $course['language']);
1407
            }
1408
            // We show the questions if
1409
            // 1. there is no question filter and the export button has not been clicked
1410
            // 2. there is a quesiton filter but the question is selected for display
1411
            if (!(isset($_POST['submit_question_filter'])) ||
1412
                (isset($_POST['submit_question_filter']) &&
1413
                    is_array($_POST['questions_filter']) &&
1414
                    in_array($row['iid'], $_POST['questions_filter']))
1415
            ) {
1416
                if (0 == $row['number_of_options'] || $compact) {
1417
                    $return .= str_replace(
1418
                        "\r\n",
1419
                        '  ',
1420
                        api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1421
                    )
1422
                    .';';
1423
                } else {
1424
                    for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1425
                        $return .= str_replace(
1426
                            "\r\n",
1427
                            '  ',
1428
                            api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1429
                        )
1430
                        .';';
1431
                    }
1432
                }
1433
            }
1434
        }
1435
1436
        $return .= "\n";
1437
        // Getting all the questions and options
1438
        $return .= ';';
1439
        // Show the fields names for user fields
1440
        if (!empty($extra_user_fields)) {
1441
            foreach ($extra_user_fields as &$field) {
1442
                if ($translate) {
1443
                    $field[3] = api_get_filtered_multilingual_HTML_string($field[3], $course['language']);
1444
                }
1445
                $return .= '"'
1446
                    .str_replace(
1447
                        "\r\n",
1448
                        '  ',
1449
                        api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES)
1450
                    )
1451
                    .'";';
1452
            }
1453
        }
1454
1455
        $sql = "SELECT DISTINCT
1456
		            survey_question.iid question_id,
1457
		            survey_question.survey_id,
1458
		            survey_question.survey_question,
1459
		            survey_question.display,
1460
		            survey_question.sort,
1461
		            survey_question.type,
1462
                    survey_question_option.iid question_option_id,
1463
                    survey_question_option.option_text,
1464
                    survey_question_option.sort as option_sort
1465
				FROM $table_survey_question survey_question
1466
				LEFT JOIN $table_survey_question_option survey_question_option
1467
				ON
1468
				    survey_question.iid = survey_question_option.question_id
1469
				WHERE
1470
				    survey_question NOT LIKE '%{{%' AND
1471
				    survey_question.type <> 'pagebreak' AND
1472
				    survey_question.survey_id = $surveyId
1473
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1474
        $result = Database::query($sql);
1475
        $possible_answers = [];
1476
        $possible_answers_type = [];
1477
        while ($row = Database::fetch_array($result)) {
1478
            // We show the options if
1479
            // 1. there is no question filter and the export button has not been clicked
1480
            // 2. there is a question filter but the question is selected for display
1481
            if ($translate) {
1482
                $row['option_text'] = api_get_filtered_multilingual_HTML_string($row['option_text'], $course['language']);
1483
            }
1484
            if (!(isset($_POST['submit_question_filter'])) || (
1485
                is_array($_POST['questions_filter']) &&
1486
                in_array($row['question_id'], $_POST['questions_filter'])
1487
            )
1488
            ) {
1489
                $row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']);
1490
                if (!$compact) {
1491
                    $return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';';
1492
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1493
                } else {
1494
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['option_text'];
1495
                }
1496
                $possible_answers_type[$row['question_id']] = $row['type'];
1497
            }
1498
        }
1499
1500
        $return .= "\n";
1501
1502
        // Getting all the answers of the users
1503
        $old_user = '';
1504
        $answers_of_user = [];
1505
        $sql = "SELECT * FROM $table_survey_answer
1506
		        WHERE
1507
		          survey_id = $surveyId
1508
		          ";
1509
        if (0 != $user_id) {
1510
            $user_id = (int) $user_id;
1511
            $sql .= " AND user = $user_id ";
1512
        }
1513
        $sql .= ' ORDER BY user ASC ';
1514
1515
        $questionIdList = array_keys($possible_answers_type);
1516
        $open_question_iterator = 1;
1517
        $result = Database::query($sql);
1518
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1519
            if (!in_array($row['question_id'], $questionIdList)) {
1520
                continue;
1521
            }
1522
            if ($old_user != $row['user'] && '' != $old_user) {
1523
                $return .= self::export_complete_report_row(
1524
                    $survey_data,
1525
                    $possible_answers,
1526
                    $answers_of_user,
1527
                    $old_user,
1528
                    true,
1529
                    $compact
1530
                );
1531
                $answers_of_user = [];
1532
            }
1533
1534
            if ('open' === $possible_answers_type[$row['question_id']] ||
1535
                'comment' === $possible_answers_type[$row['question_id']]
1536
            ) {
1537
                $temp_id = 'open'.$open_question_iterator;
1538
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1539
                $open_question_iterator++;
1540
            } else {
1541
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1542
            }
1543
            $old_user = $row['user'];
1544
        }
1545
1546
        // This is to display the last user
1547
        $return .= self::export_complete_report_row(
1548
            $survey_data,
1549
            $possible_answers,
1550
            $answers_of_user,
1551
            $old_user,
1552
            true,
1553
            $compact
1554
        );
1555
1556
        return $return;
1557
    }
1558
1559
    /**
1560
     * Add a line to the csv file.
1561
     *
1562
     * @param array $survey_data               Basic survey data (we're mostly interested in the 'anonymous' index)
1563
     * @param array $possible_options          Possible answers
1564
     * @param array $answers_of_user           User's answers
1565
     * @param mixed $user                      User ID or user details as string - Used as a string in the result
1566
     *                                         string
1567
     * @param bool  $display_extra_user_fields Whether to display user fields or not
1568
     * @param bool  $compact                   Whether to show answers as different column values (true) or one column
1569
     *                                         per option (false, default)
1570
     *
1571
     * @return string One line of the csv file
1572
     *
1573
     * @author Patrick Cool <[email protected]>, Ghent University
1574
     *
1575
     * @version February 2007
1576
     */
1577
    public static function export_complete_report_row(
1578
        CSurvey $survey,
1579
        $possible_options,
1580
        $answers_of_user,
1581
        $user,
1582
        $display_extra_user_fields = false,
1583
        $compact = false
1584
    ) {
1585
        $return = '';
1586
        if (0 == $survey->getAnonymous()) {
1587
            if (0 !== intval($user)) {
1588
                $userInfo = api_get_user_info($user);
1589
                if (!empty($userInfo)) {
1590
                    $user_displayed = $userInfo['complete_name_with_username'];
1591
                } else {
1592
                    $user_displayed = '-';
1593
                }
1594
                $return .= $user_displayed.';';
1595
            } else {
1596
                $return .= $user.';';
1597
            }
1598
        } else {
1599
            $return .= '-;'; // The user column
1600
        }
1601
1602
        if ($display_extra_user_fields) {
1603
            // Show user fields data, if any, for this user
1604
            $user_fields_values = UserManager::get_extra_user_data(
1605
                $user,
1606
                false,
1607
                false,
1608
                false,
1609
                true
1610
            );
1611
            foreach ($user_fields_values as &$value) {
1612
                $return .= '"'.str_replace('"', '""', api_html_entity_decode(strip_tags($value), ENT_QUOTES)).'";';
1613
            }
1614
        }
1615
1616
        if (is_array($possible_options)) {
1617
            foreach ($possible_options as $question_id => $possible_option) {
1618
                if (is_array($possible_option) && count($possible_option) > 0) {
1619
                    foreach ($possible_option as $option_id => &$value) {
1620
                        // For each option of this question, look if it matches the user's answer
1621
                        $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];
1622
                        $key = array_keys($my_answer_of_user);
1623
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
1624
                            // If this is an open type question (type starts by 'open'), take whatever answer is given
1625
                            $return .= '"'.
1626
                                str_replace(
1627
                                    '"',
1628
                                    '""',
1629
                                    api_html_entity_decode(
1630
                                        strip_tags(
1631
                                            $answers_of_user[$question_id][$key[0]]['option_id']
1632
                                        ),
1633
                                        ENT_QUOTES
1634
                                    )
1635
                                ).
1636
                                '";';
1637
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1638
                            //$return .= 'v';
1639
                            if ($compact) {
1640
                                // If we asked for a compact view, show only one column for the question
1641
                                // and fill it with the text of the selected option (i.e. "Yes") instead of an ID
1642
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1643
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1644
                                } else {
1645
                                    $return .= '"'.
1646
                                        str_replace(
1647
                                            '"',
1648
                                            '""',
1649
                                            api_html_entity_decode(
1650
                                                strip_tags(
1651
                                                    $possible_option[$option_id]
1652
                                                ),
1653
                                                ENT_QUOTES
1654
                                            )
1655
                                        ).
1656
                                        '";';
1657
                                }
1658
                            } else {
1659
                                // If we don't want a compact view, show one column per possible option and mark a 'v'
1660
                                // or the defined value in the corresponding column if the user selected it
1661
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1662
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1663
                                } else {
1664
                                    $return .= 'v;';
1665
                                }
1666
                            }
1667
                        } else {
1668
                            if (!$compact) {
1669
                                $return .= ';';
1670
                            }
1671
                        }
1672
                    }
1673
                }
1674
            }
1675
        }
1676
        $return .= "\n";
1677
1678
        return $return;
1679
    }
1680
1681
    public static function export_complete_report_xls(CSurvey $survey, $filename, $user_id = 0, $returnFile = false)
1682
    {
1683
        $course_id = api_get_course_int_id();
1684
        $user_id = (int) $user_id;
1685
        $surveyId = $survey->getIid();
1686
1687
        if (empty($course_id) || empty($surveyId)) {
1688
            return false;
1689
        }
1690
1691
        // Show extra fields blank space (enough for extra fields on next line)
1692
        // Show user fields section with a big th colspan that spans over all fields
1693
        $extra_user_fields = UserManager::get_extra_fields(
1694
            0,
1695
            0,
1696
            5,
1697
            'ASC',
1698
            false,
1699
            true
1700
        );
1701
        $list = [];
1702
        $num = count($extra_user_fields);
1703
        for ($i = 0; $i < $num; $i++) {
1704
            $list[0][] = '';
1705
        }
1706
1707
        $display_extra_user_fields = true;
1708
1709
        // Database table definitions
1710
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1711
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1712
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1713
1714
        // First line (questions)
1715
        $sql = "SELECT
1716
                    questions.question_id,
1717
                    questions.type,
1718
                    questions.survey_question,
1719
                    count(options.iid) as number_of_options
1720
				FROM $table_survey_question questions
1721
				LEFT JOIN $table_survey_question_option options
1722
                ON
1723
                  questions.iid = options.question_id
1724
				WHERE
1725
				    survey_question NOT LIKE '%{{%' AND
1726
				    questions.type <> 'pagebreak' AND
1727
				    questions.survey_id = $surveyId
1728
				GROUP BY questions.question_id
1729
				ORDER BY questions.sort ASC";
1730
        $result = Database::query($sql);
1731
        $line = 1;
1732
        $column = 1;
1733
        while ($row = Database::fetch_array($result)) {
1734
            // We show the questions if
1735
            // 1. there is no question filter and the export button has not been clicked
1736
            // 2. there is a quesiton filter but the question is selected for display
1737
            if (!(isset($_POST['submit_question_filter'])) ||
1738
                (isset($_POST['submit_question_filter']) && is_array($_POST['questions_filter']) &&
1739
                in_array($row['question_id'], $_POST['questions_filter']))
1740
            ) {
1741
                // We do not show comment and pagebreak question types
1742
                if ('pagebreak' !== $row['type']) {
1743
                    if (0 == $row['number_of_options'] && ('open' === $row['type'] || 'comment' === $row['type'])) {
1744
                        $list[$line][$column] = api_html_entity_decode(
1745
                            strip_tags($row['survey_question']),
1746
                            ENT_QUOTES
1747
                        );
1748
                        $column++;
1749
                    } else {
1750
                        for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1751
                            $list[$line][$column] = api_html_entity_decode(
1752
                                strip_tags($row['survey_question']),
1753
                                ENT_QUOTES
1754
                            );
1755
                            $column++;
1756
                        }
1757
                    }
1758
                }
1759
            }
1760
        }
1761
1762
        $line++;
1763
        $column = 1;
1764
        // Show extra field values
1765
        if ($display_extra_user_fields) {
1766
            // Show the fields names for user fields
1767
            foreach ($extra_user_fields as &$field) {
1768
                $list[$line][$column] = api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES);
1769
                $column++;
1770
            }
1771
        }
1772
1773
        // Getting all the questions and options (second line)
1774
        $sql = "SELECT
1775
                    survey_question.iid question_id,
1776
                    survey_question.survey_id,
1777
                    survey_question.survey_question,
1778
                    survey_question.display,
1779
                    survey_question.sort,
1780
                    survey_question.type,
1781
                    survey_question_option.iid question_option_id,
1782
                    survey_question_option.option_text,
1783
                    survey_question_option.sort as option_sort
1784
				FROM $table_survey_question survey_question
1785
				LEFT JOIN $table_survey_question_option survey_question_option
1786
				ON
1787
				    survey_question.iid = survey_question_option.question_id
1788
				WHERE
1789
				    survey_question NOT LIKE '%{{%' AND
1790
				    survey_question.type <> 'pagebreak' AND
1791
				    survey_question.survey_id = $surveyId
1792
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1793
        $result = Database::query($sql);
1794
        $possible_answers = [];
1795
        $possible_answers_type = [];
1796
        while ($row = Database::fetch_array($result)) {
1797
            // We show the options if
1798
            // 1. there is no question filter and the export button has not been clicked
1799
            // 2. there is a quesiton filter but the question is selected for display
1800
            if (!isset($_POST['submit_question_filter']) ||
1801
                (isset($_POST['questions_filter']) && is_array($_POST['questions_filter']) &&
1802
                in_array($row['question_id'], $_POST['questions_filter']))
1803
            ) {
1804
                // We do not show comment and pagebreak question types
1805
                if ('pagebreak' !== $row['type']) {
1806
                    $list[$line][$column] = api_html_entity_decode(
1807
                        strip_tags($row['option_text']),
1808
                        ENT_QUOTES
1809
                    );
1810
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1811
                    $possible_answers_type[$row['question_id']] = $row['type'];
1812
                    $column++;
1813
                }
1814
            }
1815
        }
1816
1817
        // Getting all the answers of the users
1818
        $line++;
1819
        $column = 0;
1820
        $old_user = '';
1821
        $answers_of_user = [];
1822
        $sql = "SELECT * FROM $table_survey_answer
1823
                WHERE c_id = $course_id AND survey_id = $surveyId";
1824
        if (0 != $user_id) {
1825
            $sql .= " AND user='".$user_id."' ";
1826
        }
1827
        $sql .= ' ORDER BY user ASC';
1828
1829
        $open_question_iterator = 1;
1830
        $result = Database::query($sql);
1831
        while ($row = Database::fetch_array($result)) {
1832
            if ($old_user != $row['user'] && '' != $old_user) {
1833
                $return = self::export_complete_report_row_xls(
1834
                    $survey,
1835
                    $possible_answers,
1836
                    $answers_of_user,
1837
                    $old_user,
1838
                    true
1839
                );
1840
                foreach ($return as $elem) {
1841
                    $list[$line][$column] = $elem;
1842
                    $column++;
1843
                }
1844
                $answers_of_user = [];
1845
                $line++;
1846
                $column = 0;
1847
            }
1848
            if ('open' === $possible_answers_type[$row['question_id']] || 'comment' === $possible_answers_type[$row['question_id']]) {
1849
                $temp_id = 'open'.$open_question_iterator;
1850
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1851
                $open_question_iterator++;
1852
            } else {
1853
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1854
            }
1855
            $old_user = $row['user'];
1856
        }
1857
1858
        $return = self::export_complete_report_row_xls(
1859
            $survey,
1860
            $possible_answers,
1861
            $answers_of_user,
1862
            $old_user,
1863
            true
1864
        );
1865
1866
        // this is to display the last user
1867
        if (!empty($return)) {
1868
            foreach ($return as $elem) {
1869
                $list[$line][$column] = $elem;
1870
                $column++;
1871
            }
1872
        }
1873
1874
        Export::arrayToXls($list, $filename);
1875
1876
        return null;
1877
    }
1878
1879
    /**
1880
     * Add a line to the csv file.
1881
     *
1882
     * @param array Possible answers
1883
     * @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...
1884
     * @param mixed User ID or user details as string - Used as a string in the result string
1885
     * @param bool Whether to display user fields or not
1886
     *
1887
     * @return array
1888
     */
1889
    public static function export_complete_report_row_xls(
1890
        CSurvey $survey,
1891
        $possible_options,
1892
        $answers_of_user,
1893
        $user,
1894
        $display_extra_user_fields = false
1895
    ) {
1896
        $return = [];
1897
        if (0 == $survey->getAnonymous()) {
1898
            if (0 !== (int) $user) {
1899
                $userInfo = api_get_user_info($user);
1900
                if ($userInfo) {
1901
                    $user_displayed = $userInfo['complete_name_with_username'];
1902
                } else {
1903
                    $user_displayed = '-';
1904
                }
1905
                $return[] = $user_displayed;
1906
            } else {
1907
                $return[] = $user;
1908
            }
1909
        } else {
1910
            $return[] = '-'; // The user column
1911
        }
1912
1913
        if ($display_extra_user_fields) {
1914
            //show user fields data, if any, for this user
1915
            $user_fields_values = UserManager::get_extra_user_data(
1916
                $user,
1917
                false,
1918
                false,
1919
                false,
1920
                true
1921
            );
1922
            foreach ($user_fields_values as $value) {
1923
                $return[] = api_html_entity_decode(strip_tags($value), ENT_QUOTES);
1924
            }
1925
        }
1926
1927
        if (is_array($possible_options)) {
1928
            foreach ($possible_options as $question_id => &$possible_option) {
1929
                if (is_array($possible_option) && count($possible_option) > 0) {
1930
                    foreach ($possible_option as $option_id => &$value) {
1931
                        $my_answers_of_user = $answers_of_user[$question_id] ?? [];
1932
                        $key = array_keys($my_answers_of_user);
1933
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
1934
                            $return[] = api_html_entity_decode(
1935
                                strip_tags($answers_of_user[$question_id][$key[0]]['option_id']),
1936
                                ENT_QUOTES
1937
                            );
1938
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1939
                            if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1940
                                $return[] = $answers_of_user[$question_id][$option_id]['value'];
1941
                            } else {
1942
                                $return[] = 'v';
1943
                            }
1944
                        } else {
1945
                            $return[] = '';
1946
                        }
1947
                    }
1948
                }
1949
            }
1950
        }
1951
1952
        return $return;
1953
    }
1954
1955
    /**
1956
     * This function displays the comparative report which
1957
     * allows you to compare two questions
1958
     * A comparative report creates a table where one question
1959
     * is on the x axis and a second question is on the y axis.
1960
     * In the intersection is the number of people who have
1961
     * answered positive on both options.
1962
     *
1963
     * @return string HTML code
1964
     *
1965
     * @author Patrick Cool <[email protected]>, Ghent University
1966
     *
1967
     * @version February 2007
1968
     */
1969
    public static function display_comparative_report()
1970
    {
1971
        // Allowed question types for comparative report
1972
        $allowed_question_types = [
1973
            'yesno',
1974
            'multiplechoice',
1975
            'multipleresponse',
1976
            'dropdown',
1977
            'percentage',
1978
            'score',
1979
        ];
1980
1981
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
1982
1983
        // Getting all the questions
1984
        $questions = SurveyManager::get_questions($surveyId);
1985
1986
        // Actions bar
1987
        $actions = '<a href="'.api_get_path(
1988
                WEB_CODE_PATH
1989
            ).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq()
1990
            .'">'
1991
            .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'))
1992
            .'</a>';
1993
        echo Display::toolbarAction('survey', [$actions]);
1994
1995
        // Displaying an information message that only the questions with predefined answers can be used in a comparative report
1996
        echo Display::return_message(get_lang('Only questions with predefined answers can be used'), 'normal', false);
1997
1998
        $xAxis = isset($_GET['xaxis']) ? Security::remove_XSS($_GET['xaxis']) : '';
1999
        $yAxis = isset($_GET['yaxis']) ? Security::remove_XSS($_GET['yaxis']) : '';
2000
2001
        $url = api_get_self().'?'.api_get_cidreq().'&action='.Security::remove_XSS($_GET['action'])
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($_GET['action']) 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

2001
        $url = api_get_self().'?'.api_get_cidreq().'&action='./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['action'])
Loading history...
2002
            .'&survey_id='.$surveyId.'&xaxis='.$xAxis.'&y='.$yAxis;
0 ignored issues
show
Bug introduced by
Are you sure $xAxis 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

2002
            .'&survey_id='.$surveyId.'&xaxis='./** @scrutinizer ignore-type */ $xAxis.'&y='.$yAxis;
Loading history...
Bug introduced by
Are you sure $yAxis 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

2002
            .'&survey_id='.$surveyId.'&xaxis='.$xAxis.'&y='./** @scrutinizer ignore-type */ $yAxis;
Loading history...
2003
2004
        $form = new FormValidator('compare', 'get', $url);
2005
        $form->addHidden('action', Security::remove_XSS($_GET['action']));
2006
        $form->addHidden('survey_id', $surveyId);
2007
        $optionsX = ['----'];
2008
        $optionsY = ['----'];
2009
        $defaults = [];
2010
        foreach ($questions as $key => &$question) {
2011
            // Ignored tagged questions
2012
            if ($question) {
2013
                if (false !== strpos($question['question'], '{{')) {
2014
                    $question = null;
2015
                    continue;
2016
                }
2017
            }
2018
            if (is_array($allowed_question_types)) {
2019
                if (in_array($question['type'], $allowed_question_types)) {
2020
                    if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) {
2021
                        $defaults['xaxis'] = $question['question_id'];
2022
                    }
2023
2024
                    if (isset($_GET['yaxis']) && $_GET['yaxis'] == $question['question_id']) {
2025
                        $defaults['yaxis'] = $question['question_id'];
2026
                    }
2027
2028
                    $optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2029
                    $optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2030
                }
2031
            }
2032
        }
2033
2034
        $form->addSelect('xaxis', get_lang('Select the question on the X axis'), $optionsX);
2035
        $form->addSelect('yaxis', get_lang('Select the question on the Y axis'), $optionsY);
2036
2037
        $form->addButtonSearch(get_lang('Compare questions'));
2038
        $form->setDefaults($defaults);
2039
        $form->display();
2040
2041
        // Getting all the information of the x axis
2042
        if (is_numeric($xAxis)) {
2043
            $question_x = SurveyManager::get_question($xAxis);
2044
        }
2045
2046
        // Getting all the information of the y axis
2047
        if (is_numeric($yAxis)) {
2048
            $question_y = SurveyManager::get_question($yAxis);
2049
        }
2050
2051
        if (is_numeric($xAxis) && is_numeric($yAxis) && $question_x && $question_y) {
0 ignored issues
show
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...
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...
2052
            // Getting the answers of the two questions
2053
            $answers_x = self::get_answers_of_question_by_user($surveyId, $xAxis);
2054
            $answers_y = self::get_answers_of_question_by_user($surveyId, $yAxis);
2055
2056
            // Displaying the table
2057
            $tableHtml = '<table border="1" class="table table-hover table-striped data_table">';
2058
            $xOptions = [];
2059
            // The header
2060
            $tableHtml .= '<tr>';
2061
            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...
2062
                if (0 == $ii) {
2063
                    $tableHtml .= '<th>&nbsp;</th>';
2064
                } else {
2065
                    if ('score' == $question_x['type']) {
2066
                        for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2067
                            $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'<br />'.$x.'</th>';
2068
                        }
2069
                        $x = '';
2070
                    } else {
2071
                        $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'</th>';
2072
                    }
2073
                    $optionText = strip_tags($question_x['answers'][$ii - 1]);
2074
                    $optionText = html_entity_decode($optionText);
2075
                    array_push($xOptions, trim($optionText));
2076
                }
2077
            }
2078
            $tableHtml .= '</tr>';
2079
            $chartData = [];
2080
            // The main part
2081
            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...
2082
                $currentYQuestion = strip_tags($question_y['answers'][$ij]);
2083
                $currentYQuestion = html_entity_decode($currentYQuestion);
2084
                // The Y axis is a scoring question type so we have more rows than the options (actually options * maximum score)
2085
                if ('score' == $question_y['type']) {
2086
                    for ($y = 1; $y <= $question_y['maximum_score']; $y++) {
2087
                        $tableHtml .= '<tr>';
2088
                        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...
2089
                            if ('score' == $question_x['type']) {
2090
                                for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2091
                                    if (0 == $ii) {
2092
                                        $tableHtml .= '<th>'.$question_y['answers'][($ij)].' '.$y.'</th>';
2093
                                        break;
2094
                                    } else {
2095
                                        $tableHtml .= '<td align="center">';
2096
                                        $votes = self::comparative_check(
2097
                                            $answers_x,
2098
                                            $answers_y,
2099
                                            $question_x['answersid'][($ii - 1)],
2100
                                            $question_y['answersid'][($ij)],
2101
                                            $x,
2102
                                            $y
2103
                                        );
2104
                                        $tableHtml .= $votes;
2105
                                        array_push(
2106
                                            $chartData,
2107
                                            [
2108
                                                'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2109
                                                'option' => $x,
2110
                                                'votes' => $votes,
2111
                                            ]
2112
                                        );
2113
                                        $tableHtml .= '</td>';
2114
                                    }
2115
                                }
2116
                            } else {
2117
                                if (0 == $ii) {
2118
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].' '.$y.'</th>';
2119
                                } else {
2120
                                    $tableHtml .= '<td align="center">';
2121
                                    $votes = self::comparative_check(
2122
                                        $answers_x,
2123
                                        $answers_y,
2124
                                        $question_x['answersid'][($ii - 1)],
2125
                                        $question_y['answersid'][($ij)],
2126
                                        0,
2127
                                        $y
2128
                                    );
2129
                                    $tableHtml .= $votes;
2130
                                    array_push(
2131
                                        $chartData,
2132
                                        [
2133
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2134
                                            'option' => $y,
2135
                                            'votes' => $votes,
2136
                                        ]
2137
                                    );
2138
                                    $tableHtml .= '</td>';
2139
                                }
2140
                            }
2141
                        }
2142
                        $tableHtml .= '</tr>';
2143
                    }
2144
                } else {
2145
                    // The Y axis is NOT a score question type so the number of rows = the number of options
2146
                    $tableHtml .= '<tr>';
2147
                    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...
2148
                        if ('score' == $question_x['type']) {
2149
                            for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2150
                                if (0 == $ii) {
2151
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].'</th>';
2152
                                    break;
2153
                                } else {
2154
                                    $tableHtml .= '<td align="center">';
2155
                                    $votes = self::comparative_check(
2156
                                        $answers_x,
2157
                                        $answers_y,
2158
                                        $question_x['answersid'][($ii - 1)],
2159
                                        $question_y['answersid'][($ij)],
2160
                                        $x,
2161
                                        0
2162
                                    );
2163
                                    $tableHtml .= $votes;
2164
                                    array_push(
2165
                                        $chartData,
2166
                                        [
2167
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2168
                                            'option' => $x,
2169
                                            'votes' => $votes,
2170
                                        ]
2171
                                    );
2172
                                    $tableHtml .= '</td>';
2173
                                }
2174
                            }
2175
                        } else {
2176
                            if (0 == $ii) {
2177
                                $tableHtml .= '<th>'.$question_y['answers'][($ij)].'</th>';
2178
                            } else {
2179
                                $tableHtml .= '<td align="center">';
2180
                                $votes = self::comparative_check(
2181
                                    $answers_x,
2182
                                    $answers_y,
2183
                                    $question_x['answersid'][($ii - 1)],
2184
                                    $question_y['answersid'][($ij)]
2185
                                );
2186
                                $tableHtml .= $votes;
2187
                                array_push(
2188
                                    $chartData,
2189
                                    [
2190
                                        'serie' => $xOptions[$ii - 1],
2191
                                        'option' => $currentYQuestion,
2192
                                        'votes' => $votes,
2193
                                    ]
2194
                                );
2195
                                $tableHtml .= '</td>';
2196
                            }
2197
                        }
2198
                    }
2199
                    $tableHtml .= '</tr>';
2200
                }
2201
            }
2202
            $tableHtml .= '</table>';
2203
            echo '<div id="chartContainer" class="col-md-12">';
2204
            echo self::drawChart($chartData, true);
2205
            echo '</div>';
2206
            echo $tableHtml;
2207
        }
2208
    }
2209
2210
    /**
2211
     * Get all the answers of a question grouped by user.
2212
     *
2213
     * @param int $survey_id   Survey ID
2214
     * @param int $question_id Question ID
2215
     *
2216
     * @return array Array containing all answers of all users, grouped by user
2217
     *
2218
     * @author Patrick Cool <[email protected]>, Ghent University
2219
     *
2220
     * @version February 2007 - Updated March 2008
2221
     */
2222
    public static function get_answers_of_question_by_user($survey_id, $question_id)
2223
    {
2224
        $course_id = api_get_course_int_id();
2225
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
2226
2227
        $sql = "SELECT * FROM $table_survey_answer
2228
                WHERE
2229
                  survey_id='".intval($survey_id)."' AND
2230
                  question_id='".intval($question_id)."'
2231
                ORDER BY USER ASC";
2232
        $result = Database::query($sql);
2233
        $return = [];
2234
        while ($row = Database::fetch_array($result)) {
2235
            if (0 == $row['value']) {
2236
                $return[$row['user']][] = $row['option_id'];
2237
            } else {
2238
                $return[$row['user']][] = $row['option_id'].'*'.$row['value'];
2239
            }
2240
        }
2241
2242
        return $return;
2243
    }
2244
2245
    /**
2246
     * Count the number of users who answer positively on both options.
2247
     *
2248
     * @param array All answers of the x axis
2249
     * @param array All answers of the y axis
2250
     * @param int x axis value (= the option_id of the first question)
2251
     * @param int y axis value (= the option_id of the second question)
2252
     *
2253
     * @return int Number of users who have answered positively to both options
2254
     *
2255
     * @author Patrick Cool <[email protected]>, Ghent University
2256
     *
2257
     * @version February 2007
2258
     */
2259
    public static function comparative_check(
2260
        $answers_x,
2261
        $answers_y,
2262
        $option_x,
2263
        $option_y,
2264
        $value_x = 0,
2265
        $value_y = 0
2266
    ) {
2267
        if (0 == $value_x) {
2268
            $check_x = $option_x;
2269
        } else {
2270
            $check_x = $option_x.'*'.$value_x;
2271
        }
2272
        if (0 == $value_y) {
2273
            $check_y = $option_y;
2274
        } else {
2275
            $check_y = $option_y.'*'.$value_y;
2276
        }
2277
2278
        $counter = 0;
2279
        if (is_array($answers_x)) {
2280
            foreach ($answers_x as $user => &$answers) {
2281
                // Check if the user has given $option_x as answer
2282
                if (in_array($check_x, $answers)) {
2283
                    // Check if the user has given $option_y as an answer
2284
                    if (!is_null($answers_y[$user]) &&
2285
                        in_array($check_y, $answers_y[$user])
2286
                    ) {
2287
                        $counter++;
2288
                    }
2289
                }
2290
            }
2291
        }
2292
2293
        return $counter;
2294
    }
2295
2296
    public static function saveInviteMail(CSurvey $survey, $content, $subject, $remind)
2297
    {
2298
        // Database table definition
2299
        if ($remind) {
2300
            $survey->setReminderMail($content);
2301
        } else {
2302
            $survey->setInviteMail($content);
2303
        }
2304
2305
        $survey->setMailSubject($subject);
2306
        $em = Database::getManager();
2307
        $em->persist($survey);
2308
        $em->flush();
2309
    }
2310
2311
    /**
2312
     * This function saves all the invitations of course users
2313
     * and additional users in the database
2314
     * and sends the invitations by email.
2315
     *
2316
     * @param int    $surveyId
2317
     * @param array  $users_array       Users array can be both a list of course uids AND a list of additional email
2318
     *                                  addresses
2319
     * @param string $invitation_title  title of the mail
2320
     * @param string $invitation_text   text of the mail has to contain a **link** string or
2321
     *                                  this will automatically be added to the end
2322
     * @param int    $reminder
2323
     * @param bool   $sendmail
2324
     * @param int    $remindUnAnswered
2325
     * @param bool   $isAdditionalEmail
2326
     * @param bool   $hideLink
2327
     *
2328
     * @author Patrick Cool <[email protected]>, Ghent University
2329
     * @author Julio Montoya - Adding auto-generated link support
2330
     *
2331
     * @version January 2007
2332
     */
2333
    public static function saveInvitations(
2334
        CSurvey $survey,
2335
        $users_array,
2336
        $invitation_title,
2337
        $invitation_text,
2338
        $reminder = 0,
2339
        $sendmail = false,
2340
        $remindUnAnswered = 0,
2341
        $isAdditionalEmail = false,
2342
        $hideLink = false
2343
    ) {
2344
        $surveyId = $survey->getIid();
2345
2346
        if (!is_array($users_array)) {
2347
            return 0;
2348
        }
2349
        $course = api_get_course_entity();
2350
        $session = api_get_session_entity();
2351
        $survey_invitations = self::get_invitations($surveyId);
2352
        $already_invited = self::get_invited_users($survey);
2353
2354
        // Remind unanswered is a special version of remind all reminder
2355
        $exclude_users = [];
2356
        if (1 == $remindUnAnswered) {
2357
            // Remind only unanswered users
2358
            $reminder = 1;
2359
            $exclude_users = SurveyManager::get_people_who_filled_survey($surveyId);
2360
        }
2361
2362
        $counter = 0; // Nr of invitations "sent" (if sendmail option)
2363
        $course_id = api_get_course_int_id();
2364
        $session_id = api_get_session_id();
2365
2366
        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...
2367
            $result = AbstractResource::separateUsersGroups($users_array);
2368
            $groupList = $result['groups'];
2369
            $users_array = $result['users'];
2370
2371
            foreach ($groupList as $groupId) {
2372
                $group = api_get_group_entity($groupId);
2373
                $userGroupList = GroupManager::getStudents($groupId, true);
2374
                $userGroupIdList = array_column($userGroupList, 'user_id');
2375
                $users_array = array_merge($users_array, $userGroupIdList);
2376
2377
                /*$params = [
2378
                    'c_id' => $course_id,
2379
                    'session_id' => $session_id,
2380
                    'group_id' => $groupId,
2381
                    'survey_code' => $survey_data['code'],
2382
                ];*/
2383
2384
                $invitationExists = self::invitationExists(
2385
                    $course_id,
2386
                    $session_id,
2387
                    $groupId,
2388
                    $survey->getIid()
2389
                );
2390
                if (empty($invitationExists)) {
2391
                    self::saveInvitation(
2392
                        '',
2393
                        '',
2394
                        api_get_utc_datetime(time(), false, true),
2395
                        $survey,
2396
                        $course,
2397
                        $session,
2398
                        $group
2399
                    );
2400
                }
2401
            }
2402
        }
2403
2404
        $users_array = array_unique($users_array);
2405
        foreach ($users_array as $value) {
2406
            if (empty($value)) {
2407
                continue;
2408
            }
2409
2410
            // Skip user if reminding only unanswered people
2411
            if (in_array($value, $exclude_users)) {
2412
                continue;
2413
            }
2414
2415
            // Get the unique invitation code if we already have it
2416
            if (1 == $reminder && array_key_exists($value, $survey_invitations)) {
2417
                $invitation_code = $survey_invitations[$value]['invitation_code'];
2418
            } else {
2419
                $invitation_code = md5($value.microtime());
2420
            }
2421
            $new_user = false; // User not already invited
2422
            // Store the invitation if user_id not in $already_invited['course_users'] OR
2423
            // email is not in $already_invited['additional_users']
2424
            $addit_users_array = isset($already_invited['additional_users']) && !empty($already_invited['additional_users'])
2425
                    ? explode(';', $already_invited['additional_users'])
2426
                    : [];
2427
            $my_alredy_invited = $already_invited['course_users'] ?? [];
2428
            if ((is_numeric($value) && !in_array($value, $my_alredy_invited)) ||
2429
                (!is_numeric($value) && !in_array($value, $addit_users_array))
2430
            ) {
2431
                $new_user = true;
2432
                if (!array_key_exists($value, $survey_invitations)) {
2433
                    self::saveInvitation(
2434
                        api_get_user_entity($value),
2435
                        $invitation_code,
2436
                        api_get_utc_datetime(time(), null, true),
2437
                        $survey,
2438
                        $course,
2439
                        $session
2440
                    );
2441
                }
2442
            }
2443
2444
            // Send the email if checkboxed
2445
            if (($new_user || 1 == $reminder) && $sendmail) {
2446
                // Make a change for absolute url
2447
                if (isset($invitation_text)) {
2448
                    $invitation_text = api_html_entity_decode($invitation_text, ENT_QUOTES);
2449
                    $invitation_text = str_replace('src="../../', 'src="'.api_get_path(WEB_PATH), $invitation_text);
2450
                    $invitation_text = trim(stripslashes($invitation_text));
2451
                }
2452
                self::sendInvitationMail(
2453
                    $survey,
2454
                    $value,
2455
                    $course,
2456
                    $invitation_code,
2457
                    $invitation_title,
2458
                    $invitation_text,
2459
                    $hideLink
2460
                );
2461
                $counter++;
2462
            }
2463
        }
2464
2465
        return $counter; // Number of invitations sent
2466
    }
2467
2468
    public static function saveInvitation(
2469
        User $user,
2470
        $invitationCode,
2471
        $reminderDate,
2472
        CSurvey $survey,
2473
        Course $course,
2474
        SessionEntity $session = null,
2475
        CGroup $group = null
2476
    ): ?CSurveyInvitation {
2477
        $invitation = new CSurveyInvitation();
2478
        $invitation
2479
            ->setUser($user)
2480
            ->setInvitationCode($invitationCode)
2481
            ->setReminderDate($reminderDate)
2482
            ->setSurvey($survey)
2483
            ->setCourse($course)
2484
            ->setSession($session)
2485
            ->setGroup($group)
2486
        ;
2487
2488
        $em = Database::getManager();
2489
        $em->persist($invitation);
2490
        $em->flush();
2491
2492
        return $invitation;
2493
    }
2494
2495
    /**
2496
     * @param int $courseId
2497
     * @param int $sessionId
2498
     * @param int $groupId
2499
     * @param int $surveyId
2500
     *
2501
     * @return int
2502
     */
2503
    public static function invitationExists($courseId, $sessionId, $groupId, $surveyId)
2504
    {
2505
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
2506
        $courseId = (int) $courseId;
2507
        $sessionId = (int) $sessionId;
2508
        $groupId = (int) $groupId;
2509
        $surveyId = (int) $surveyId;
2510
2511
        $sql = "SELECT iid FROM $table
2512
                WHERE
2513
                    c_id = $courseId AND
2514
                    session_id = $sessionId AND
2515
                    group_id = $groupId AND
2516
                    survey_id = $surveyId
2517
                ";
2518
        $result = Database::query($sql);
2519
2520
        return Database::num_rows($result);
2521
    }
2522
2523
    /**
2524
     * Send the invitation by mail.
2525
     *
2526
     * @param int invitedUser - the userId (course user) or emailaddress of additional user
2527
     * @param string $invitation_code - the unique invitation code for the URL
2528
     */
2529
    public static function sendInvitationMail(
2530
        CSurvey $survey,
2531
        $invitedUser,
2532
        Course $course,
2533
        $invitation_code,
2534
        $invitation_title,
2535
        $invitation_text,
2536
        $hideLink = false
2537
    ) {
2538
        $_user = api_get_user_info();
2539
        $sessionId = api_get_session_id();
2540
2541
        // Replacing the **link** part with a valid link for the user
2542
        $link = self::generateFillSurveyLink($survey, $invitation_code, $course, $sessionId);
2543
        if ($hideLink) {
2544
            $full_invitation_text = str_replace('**link**', '', $invitation_text);
2545
        } else {
2546
            $text_link = '<a href="'.$link.'">'.get_lang('Click here to answer the survey')."</a><br />\r\n<br />\r\n"
2547
                .get_lang('or copy paste the following url :')." <br /> \r\n <br /> \r\n ".$link;
2548
2549
            $replace_count = 0;
2550
            $full_invitation_text = api_str_ireplace('**link**', $text_link, $invitation_text, $replace_count);
2551
            if ($replace_count < 1) {
2552
                $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

2552
                $full_invitation_text = /** @scrutinizer ignore-type */ $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
Loading history...
2553
            }
2554
        }
2555
2556
        // Sending the mail
2557
        $sender_name = api_get_person_name($_user['firstName'], $_user['lastName'], null, PERSON_NAME_EMAIL_ADDRESS);
2558
        $sender_email = $_user['mail'];
2559
        $sender_user_id = api_get_user_id();
2560
2561
        $replyto = [];
2562
        if ('noreply' === api_get_setting('survey_email_sender_noreply')) {
2563
            $noreply = api_get_setting('noreply_email_address');
2564
            if (!empty($noreply)) {
2565
                $replyto['Reply-to'] = $noreply;
2566
                $sender_name = $noreply;
2567
                $sender_email = $noreply;
2568
                $sender_user_id = null;
2569
            }
2570
        }
2571
2572
        // Optionally: finding the e-mail of the course user
2573
        if (is_numeric($invitedUser)) {
2574
            MessageManager::send_message(
2575
                $invitedUser,
2576
                $invitation_title,
2577
                $full_invitation_text,
2578
                [],
2579
                [],
2580
                null,
2581
                null,
2582
                null,
2583
                null,
2584
                $sender_user_id,
2585
                true
2586
            );
2587
        } else {
2588
            @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

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