Passed
Push — master ( d9f8b0...e02700 )
by Julito
09:47
created

SurveyUtil::display_survey_search_form()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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

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