Completed
Push — master ( 162b1e...50d94b )
by Julito
11:02
created

SurveyUtil::displayUserReport()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 53
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 39
nop 3
dl 0
loc 53
rs 8.6737
c 0
b 0
f 0
nc 9

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $userInfo 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...
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
            $insertId = Database::insert($table, $params);
2430
            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...
2431
                $sql = "UPDATE $table
2432
                        SET survey_invitation_id = $insertId
2433
                        WHERE iid = $insertId";
2434
                Database::query($sql);
2435
            }
2436
2437
            return $insertId;
2438
        }
2439
2440
        return false;
2441
    }
2442
2443
    /**
2444
     * @param int    $courseId
2445
     * @param int    $sessionId
2446
     * @param int    $groupId
2447
     * @param string $surveyCode
2448
     *
2449
     * @return int
2450
     */
2451
    public static function invitationExists($courseId, $sessionId, $groupId, $surveyCode)
2452
    {
2453
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
2454
        $courseId = (int) $courseId;
2455
        $sessionId = (int) $sessionId;
2456
        $groupId = (int) $groupId;
2457
        $surveyCode = Database::escape_string($surveyCode);
2458
2459
        $sql = "SELECT survey_invitation_id FROM $table
2460
                WHERE
2461
                    c_id = $courseId AND
2462
                    session_id = $sessionId AND
2463
                    group_id = $groupId AND
2464
                    survey_code = '$surveyCode'
2465
                ";
2466
        $result = Database::query($sql);
2467
2468
        return Database::num_rows($result);
2469
    }
2470
2471
    /**
2472
     * Send the invitation by mail.
2473
     *
2474
     * @param int invitedUser - the userId (course user) or emailaddress of additional user
2475
     * $param string $invitation_code - the unique invitation code for the URL
2476
     */
2477
    public static function send_invitation_mail(
2478
        $invitedUser,
2479
        $invitation_code,
2480
        $invitation_title,
2481
        $invitation_text,
2482
        $hideLink = false
2483
    ) {
2484
        $_user = api_get_user_info();
2485
        $_course = api_get_course_info();
2486
        $sessionId = api_get_session_id();
2487
2488
        // Replacing the **link** part with a valid link for the user
2489
        $link = self::generateFillSurveyLink($invitation_code, $_course, $sessionId);
2490
        if ($hideLink) {
2491
            $full_invitation_text = str_replace('**link**', '', $invitation_text);
2492
        } else {
2493
            $text_link = '<a href="'.$link.'">'.get_lang('ClickHereToAnswerTheSurvey')."</a><br />\r\n<br />\r\n"
2494
                .get_lang('OrCopyPasteTheFollowingUrl')." <br /> \r\n <br /> \r\n ".$link;
2495
2496
            $replace_count = 0;
2497
            $full_invitation_text = api_str_ireplace('**link**', $text_link, $invitation_text, $replace_count);
2498
            if ($replace_count < 1) {
2499
                $full_invitation_text = $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
2500
            }
2501
        }
2502
2503
        // Sending the mail
2504
        $sender_name = api_get_person_name($_user['firstName'], $_user['lastName'], null, PERSON_NAME_EMAIL_ADDRESS);
2505
        $sender_email = $_user['mail'];
2506
        $sender_user_id = api_get_user_id();
2507
2508
        $replyto = [];
2509
        if (api_get_setting('survey_email_sender_noreply') == 'noreply') {
2510
            $noreply = api_get_setting('noreply_email_address');
2511
            if (!empty($noreply)) {
2512
                $replyto['Reply-to'] = $noreply;
2513
                $sender_name = $noreply;
2514
                $sender_email = $noreply;
2515
                $sender_user_id = null;
2516
            }
2517
        }
2518
2519
        // Optionally: finding the e-mail of the course user
2520
        if (is_numeric($invitedUser)) {
2521
            MessageManager::send_message(
2522
                $invitedUser,
2523
                $invitation_title,
2524
                $full_invitation_text,
2525
                [],
2526
                [],
2527
                null,
2528
                null,
2529
                null,
2530
                null,
2531
                $sender_user_id,
2532
                true
2533
            );
2534
        } else {
2535
            @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

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