Completed
Push — master ( 1a5e2c...34133a )
by Julito
08:10
created

SurveyUtil::store_answer()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 57
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 30
c 0
b 0
f 0
nc 13
nop 7
dl 0
loc 57
rs 8.8177

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
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CourseBundle\Entity\CSurvey;
6
use Chamilo\CourseBundle\Entity\CSurveyAnswer;
7
use ChamiloSession as Session;
8
9
/**
10
 * This class offers a series of general utility functions for survey querying and display.
11
 */
12
class SurveyUtil
13
{
14
    /**
15
     * Checks whether the given survey has a pagebreak question as the first
16
     * or the last question.
17
     * If so, break the current process, displaying an error message.
18
     *
19
     * @param int  $survey_id Survey ID (database ID)
20
     * @param bool $continue  Optional. Whether to continue the current
21
     *                        process or exit when breaking condition found. Defaults to true (do not break).
22
     */
23
    public static function check_first_last_question($survey_id, $continue = true)
24
    {
25
        // Table definitions
26
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
27
        $course_id = api_get_course_int_id();
28
        $survey_id = (int) $survey_id;
29
30
        // Getting the information of the question
31
        $sql = "SELECT * FROM $tbl_survey_question
32
                WHERE c_id = $course_id AND survey_id='".$survey_id."'
33
                ORDER BY sort ASC";
34
        $result = Database::query($sql);
35
        $total = Database::num_rows($result);
36
        $counter = 1;
37
        $error = false;
38
        while ($row = Database::fetch_array($result, 'ASSOC')) {
39
            if (1 == $counter && 'pagebreak' == $row['type']) {
40
                echo Display::return_message(get_lang('The page break cannot be the first'), 'error', false);
41
                $error = true;
42
            }
43
            if ($counter == $total && 'pagebreak' == $row['type']) {
44
                echo Display::return_message(get_lang('The page break cannot be the last one'), 'error', false);
45
                $error = true;
46
            }
47
            $counter++;
48
        }
49
50
        if (!$continue && $error) {
51
            Display::display_footer();
52
            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...
53
        }
54
    }
55
56
    /**
57
     * This function removes an (or multiple) answer(s) of a user on a question of a survey.
58
     *
59
     * @param mixed   The user id or email of the person who fills the survey
60
     * @param int The survey id
61
     * @param int The question id
62
     * @param int The option id
63
     *
64
     * @author Patrick Cool <[email protected]>, Ghent University
65
     *
66
     * @version January 2007
67
     */
68
    public static function remove_answer($user, $survey_id, $question_id, $course_id)
69
    {
70
        $course_id = intval($course_id);
71
        // table definition
72
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
73
        $sql = "DELETE FROM $table
74
				WHERE
75
				    c_id = $course_id AND
76
                    user = '".Database::escape_string($user)."' AND
77
                    survey_id = '".intval($survey_id)."' AND
78
                    question_id = '".intval($question_id)."'";
79
        Database::query($sql);
80
    }
81
82
    /**
83
     * This function stores an answer of a user on a question of a survey.
84
     *
85
     * @param mixed   The user id or email of the person who fills the survey
86
     * @param int Survey id
87
     * @param int Question id
88
     * @param int Option id
89
     * @param string  Option value
90
     * @param array $survey_data Survey data settings
91
     *
92
     * @return bool False if insufficient data, true otherwise
93
     *
94
     * @author Patrick Cool <[email protected]>, Ghent University
95
     *
96
     * @version January 2007
97
     */
98
    public static function store_answer(
99
        $user,
100
        $survey_id,
101
        $question_id,
102
        $option_id,
103
        $option_value,
104
        $survey_data,
105
        $otherOption = ''
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 (1 == $survey_data['anonymous']) {
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
        if (!empty($otherOption)) {
127
            $option_id = $option_id.'@:@'.$otherOption;
128
        }
129
130
131
        $answer = new CSurveyAnswer();
132
        $answer
133
            ->setCId($survey_data['c_id'])
134
            ->setUser($user)
135
            ->setSurveyId($survey_id)
136
            ->setQuestionId($question_id)
137
            ->setOptionId($option_id)
138
            ->setValue($option_value)
139
        ;
140
141
        $em = Database::getManager();
142
        $em->persist($answer);
143
        $em->flush();
144
145
        $insertId = $answer->getIid();
146
        if ($insertId) {
147
            $sql = "UPDATE $table_survey_answer SET answer_id = $insertId
148
                WHERE iid = $insertId";
149
            Database::query($sql);
150
151
            return true;        
152
        }        
153
154
        return false;
155
    }
156
157
    /**
158
     * This function checks the parameters that are used in this page.
159
     *
160
     * @return string $people_filled The header, an error and the footer if any parameter fails, else it returns true
161
     *
162
     * @author Patrick Cool <[email protected]>, Ghent University
163
     *
164
     * @version February 2007
165
     */
166
    public static function check_parameters($people_filled)
167
    {
168
        $error = false;
169
170
        // Getting the survey data
171
        $survey_data = SurveyManager::get_survey($_GET['survey_id']);
172
173
        // $_GET['survey_id'] has to be numeric
174
        if (!is_numeric($_GET['survey_id'])) {
175
            $error = get_lang('Unknown survey id');
176
        }
177
178
        // $_GET['action']
179
        $allowed_actions = [
180
            'overview',
181
            'questionreport',
182
            'userreport',
183
            'comparativereport',
184
            'completereport',
185
            'deleteuserreport',
186
        ];
187
        if (isset($_GET['action']) && !in_array($_GET['action'], $allowed_actions)) {
188
            $error = get_lang('Action not allowed');
189
        }
190
191
        // User report
192
        if (isset($_GET['action']) && 'userreport' == $_GET['action']) {
193
            if (0 == $survey_data['anonymous']) {
194
                foreach ($people_filled as $key => &$value) {
195
                    $people_filled_userids[] = $value['invited_user'];
196
                }
197
            } else {
198
                $people_filled_userids = $people_filled;
199
            }
200
201
            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...
202
                $error = get_lang('Unknow user');
203
            }
204
        }
205
206
        // Question report
207
        if (isset($_GET['action']) && 'questionreport' == $_GET['action']) {
208
            if (isset($_GET['question']) && !is_numeric($_GET['question'])) {
209
                $error = get_lang('Unknown question');
210
            }
211
        }
212
213
        if ($error) {
214
            $tool_name = get_lang('Reporting');
215
            Display::addFlash(
216
                Display::return_message(
217
                    get_lang('Error').': '.$error,
218
                    'error',
219
                    false
220
                )
221
            );
222
            Display::display_header($tool_name);
223
            Display::display_footer();
224
            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...
225
        } else {
226
            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...
227
        }
228
    }
229
230
    /**
231
     * This function deals with the action handling.
232
     *
233
     * @param array $survey_data
234
     * @param array $people_filled
235
     *
236
     * @author Patrick Cool <[email protected]>, Ghent University
237
     *
238
     * @version February 2007
239
     */
240
    public static function handle_reporting_actions($survey_data, $people_filled)
241
    {
242
        $action = isset($_GET['action']) ? $_GET['action'] : '';
243
244
        // Getting the number of question
245
        $questions = SurveyManager::get_questions($survey_data['survey_id']);
246
247
        $counter = 0;
248
        foreach ($questions as $key => $value) {
249
            if ($value['type'] !== 'pagebreak') {
250
                $counter++;
251
            }
252
        }
253
254
        $survey_data['number_of_questions'] = $counter;
255
256
        switch ($action) {
257
            case 'questionreport':
258
                self::display_question_report($survey_data);
259
                break;
260
            case 'userreport':
261
                self::displayUserReport($survey_data, $people_filled);
262
                break;
263
            case 'comparativereport':
264
                self::display_comparative_report();
265
                break;
266
            case 'completereport':
267
                echo self::displayCompleteReport($survey_data);
268
                break;
269
            case 'deleteuserreport':
270
                self::delete_user_report($_GET['survey_id'], $_GET['user']);
271
                break;
272
        }
273
    }
274
275
    /**
276
     * This function deletes the report of an user who wants to retake the survey.
277
     *
278
     * @param int $survey_id
279
     * @param int $user_id
280
     *
281
     * @author Christian Fasanando Flores <[email protected]>
282
     *
283
     * @version November 2008
284
     */
285
    public static function delete_user_report($survey_id, $user_id)
286
    {
287
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
288
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
289
        $table_survey = Database::get_course_table(TABLE_SURVEY);
290
291
        $course_id = api_get_course_int_id();
292
        $survey_id = (int) $survey_id;
293
        $user_id = Database::escape_string($user_id);
294
295
        if (!empty($survey_id) && !empty($user_id)) {
296
            // delete data from survey_answer by user_id and survey_id
297
            $sql = "DELETE FROM $table_survey_answer
298
			        WHERE c_id = $course_id AND survey_id = '".$survey_id."' AND user = '".$user_id."'";
299
            Database::query($sql);
300
            // update field answered from survey_invitation by user_id and survey_id
301
            $sql = "UPDATE $table_survey_invitation SET answered = '0'
302
			        WHERE
303
			            c_id = $course_id AND
304
			            survey_code = (
305
                            SELECT code FROM $table_survey
306
                            WHERE
307
                                c_id = $course_id AND
308
                                survey_id = '".$survey_id."'
309
                        ) AND
310
			            user = '".$user_id."'";
311
            $result = Database::query($sql);
312
        }
313
314
        if (false !== $result) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
315
            $message = get_lang('The user\'s answers to the survey have been succesfully removed.').'<br />
316
					<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
317
                .$survey_id.'">'.
318
                get_lang('Go back').'</a>';
319
            echo Display::return_message($message, 'confirmation', false);
320
        }
321
    }
322
323
    /**
324
     * @param array $survey_data
325
     * @param array $people_filled
326
     *
327
     * @return string
328
     */
329
    public static function displayUserReportForm($survey_data, $people_filled)
330
    {
331
        $surveyId = $survey_data['survey_id'];
332
333
        if (empty($survey_data)) {
334
            return '';
335
        }
336
337
        // Step 1: selection of the user
338
        echo "<script>
339
        function jumpMenu(targ,selObj,restore) {
340
            eval(targ+\".location='\"+selObj.options[selObj.selectedIndex].value+\"'\");
341
            if (restore) selObj.selectedIndex=0;
342
        }
343
		</script>";
344
        echo get_lang('Select user who filled the survey').'<br />';
345
        echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
346
        echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
347
            .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
348
            .get_lang('User').'</option>';
349
350
        foreach ($people_filled as $key => &$person) {
351
            if (0 == $survey_data['anonymous']) {
352
                $name = $person['user_info']['complete_name_with_username'];
353
                $id = $person['user_id'];
354
                if ('' == $id) {
355
                    $id = $person['invited_user'];
356
                    $name = $person['invited_user'];
357
                }
358
            } else {
359
                $name = get_lang('Anonymous').' '.($key + 1);
360
                $id = $person;
361
            }
362
            echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
363
                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&user='
364
                .Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
365
            if (isset($_GET['user']) && $_GET['user'] == $id) {
366
                echo 'selected="selected"';
367
            }
368
            echo '>'.$name.'</option>';
369
        }
370
        echo '</select>';
371
    }
372
373
    /**
374
     * @param int   $userId
375
     * @param array $survey_data
376
     * @param bool  $addMessage
377
     */
378
    public static function displayUserReportAnswers($userId, $survey_data, $addMessage = true)
379
    {
380
        // Database table definitions
381
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
382
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
383
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
384
        $course_id = (int) $survey_data['c_id'];
385
        $surveyId = (int) $survey_data['survey_id'];
386
        $userId = Database::escape_string($userId);
387
388
        $content = '';
389
        // Step 2: displaying the survey and the answer of the selected users
390
        if (!empty($userId)) {
391
            if ($addMessage) {
392
                $content .= Display::return_message(
393
                    get_lang('This screen displays an exact copy of the form as it was filled by the user'),
394
                    'normal',
395
                    false
396
                );
397
            }
398
399
            // Getting all the questions and options
400
            $sql = "SELECT
401
			            survey_question.question_id,
402
			            survey_question.survey_id,
403
			            survey_question.survey_question,
404
			            survey_question.display,
405
			            survey_question.max_value,
406
			            survey_question.sort,
407
			            survey_question.type,
408
                        survey_question_option.question_option_id,
409
                        survey_question_option.option_text,
410
                        survey_question_option.sort as option_sort
411
					FROM $table_survey_question survey_question
412
					LEFT JOIN $table_survey_question_option survey_question_option
413
					ON
414
					    survey_question.question_id = survey_question_option.question_id AND
415
					    survey_question_option.c_id = $course_id
416
					WHERE
417
					    survey_question NOT LIKE '%{{%' AND
418
					    survey_question.survey_id = '".$surveyId."' AND
419
                        survey_question.c_id = $course_id
420
					ORDER BY survey_question.sort, survey_question_option.sort ASC";
421
            $result = Database::query($sql);
422
            while ($row = Database::fetch_array($result, 'ASSOC')) {
423
                if ('pagebreak' != $row['type']) {
424
                    $questions[$row['sort']]['question_id'] = $row['question_id'];
425
                    $questions[$row['sort']]['survey_id'] = $row['survey_id'];
426
                    $questions[$row['sort']]['survey_question'] = $row['survey_question'];
427
                    $questions[$row['sort']]['display'] = $row['display'];
428
                    $questions[$row['sort']]['type'] = $row['type'];
429
                    $questions[$row['sort']]['maximum_score'] = $row['max_value'];
430
                    $questions[$row['sort']]['options'][$row['question_option_id']] = $row['option_text'];
431
                }
432
            }
433
434
            // Getting all the answers of the user
435
            $sql = "SELECT * FROM $table_survey_answer
436
			        WHERE
437
                        c_id = $course_id AND
438
                        survey_id = '".$surveyId."' AND
439
                        user = '".$userId."'";
440
            $result = Database::query($sql);
441
            while ($row = Database::fetch_array($result, 'ASSOC')) {
442
                $answers[$row['question_id']][] = $row['option_id'];
443
                $all_answers[$row['question_id']][] = $row;
444
            }
445
446
            // Displaying all the questions
447
            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...
448
                // If the question type is a scoring then we have to format the answers differently
449
                switch ($question['type']) {
450
                    case 'score':
451
                        $finalAnswer = [];
452
                        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...
453
                            foreach ($all_answers[$question['question_id']] as $key => &$answer_array) {
454
                                $finalAnswer[$answer_array['option_id']] = $answer_array['value'];
455
                            }
456
                        }
457
                        break;
458
                    case 'multipleresponse':
459
                        $finalAnswer = isset($answers[$question['question_id']])
460
                            ? $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...
461
                            : '';
462
                        break;
463
                    default:
464
                        $finalAnswer = '';
465
                        if (isset($all_answers[$question['question_id']])) {
466
                            $finalAnswer = $all_answers[$question['question_id']][0]['option_id'];
467
                        }
468
                        break;
469
                }
470
471
                $display = survey_question::createQuestion($question['type']);
472
                $url = api_get_self();
473
                $form = new FormValidator('question', 'post', $url);
474
                $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
475
                $form->addHtml($question['survey_question']);
476
                $display->render($form, $question, $finalAnswer);
477
                $form->addHtml('</div></div>');
478
                $content .= $form->returnForm();
479
            }
480
        }
481
482
        return $content;
483
    }
484
485
    /**
486
     * This function displays the user report which is basically nothing more
487
     * than a one-page display of all the questions
488
     * of the survey that is filled with the answers of the person who filled the survey.
489
     *
490
     * @return string html code of the one-page survey with the answers of the selected user
491
     *
492
     * @author Patrick Cool <[email protected]>, Ghent University
493
     *
494
     * @version February 2007 - Updated March 2008
495
     */
496
    public static function displayUserReport($survey_data, $people_filled, $addActionBar = true)
497
    {
498
        if (empty($survey_data)) {
499
            return '';
500
        }
501
502
        $surveyId = $survey_data['survey_id'];
503
        $reportingUrl = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
504
505
        // Actions bar
506
        if ($addActionBar) {
507
            echo '<div class="actions">';
508
            echo '<a href="'.$reportingUrl.'">'.
509
                Display::return_icon(
510
                    'back.png',
511
                    get_lang('Back to').' '.get_lang('Reporting overview'),
512
                    '',
513
                    ICON_SIZE_MEDIUM
514
                )
515
                .'</a>';
516
            if (isset($_GET['user'])) {
517
                if (api_is_allowed_to_edit()) {
518
                    // The delete link
519
                    echo '<a href="'.$reportingUrl.'&action=deleteuserreport&user='.Security::remove_XSS($_GET['user']).'" >'.
520
                        Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_MEDIUM).'</a>';
521
                }
522
523
                // Export the user report
524
                echo '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
525
                    .Display::return_icon('export_csv.png', get_lang('CSV export'), '', ICON_SIZE_MEDIUM).'</a> ';
526
                echo '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
527
                    .Display::return_icon('export_excel.png', get_lang('Excel export'), '', ICON_SIZE_MEDIUM).'</a> ';
528
                echo '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
529
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
530
                    .Security::remove_XSS($_GET['user']).'">';
531
                echo '<input type="hidden" name="export_report" value="export_report">';
532
                echo '<input type="hidden" name="export_format" value="csv">';
533
                echo '</form>';
534
                echo '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
535
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
536
                    .Security::remove_XSS($_GET['user']).'">';
537
                echo '<input type="hidden" name="export_report" value="export_report">';
538
                echo '<input type="hidden" name="export_format" value="xls">';
539
                echo '</form>';
540
                echo '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
541
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
542
            }
543
            echo '</div>';
544
        }
545
546
        echo self::displayUserReportForm($survey_data, $people_filled);
547
        if (isset($_GET['user'])) {
548
            echo self::displayUserReportAnswers($_GET['user'], $survey_data);
549
        }
550
    }
551
552
    /**
553
     * This function displays the report by question.
554
     *
555
     * It displays a table with all the options of the question and the number of users who have answered positively on
556
     * the option. The number of users who answered positive on a given option is expressed in an absolute number, in a
557
     * percentage of the total and graphically using bars By clicking on the absolute number you get a list with the
558
     * persons who have answered this. You can then click on the name of the person and you will then go to the report
559
     * by user where you see all the answers of that user.
560
     *
561
     * @param    array    All the survey data
562
     *
563
     * @return string html code that displays the report by question
564
     *
565
     * @todo allow switching between horizontal and vertical.
566
     * @todo multiple response: percentage are probably not OK
567
     * @todo the question and option text have to be shortened and should expand when the user clicks on it.
568
     * @todo the pagebreak and comment question types should not be shown => removed from $survey_data before
569
     *
570
     * @author Patrick Cool <[email protected]>, Ghent University
571
     *
572
     * @version February 2007 - Updated March 2008
573
     */
574
    public static function display_question_report($survey_data)
575
    {
576
        $singlePage = isset($_GET['single_page']) ? (int) $_GET['single_page'] : 0;
577
        // Determining the offset of the sql statement (the n-th question of the survey)
578
        $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question'];
579
        $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0;
580
        $surveyId = (int) $survey_data['survey_id'];
581
        $action = Security::remove_XSS($_GET['action']);
582
        $course_id = api_get_course_int_id();
583
584
        // Database table definitions
585
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
586
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
587
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
588
        $questions = [];
589
590
        echo '<div class="actions">';
591
        echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'.
592
            Display::return_icon(
593
                'back.png',
594
                get_lang('Back to').' '.get_lang('Reporting overview'),
595
                '',
596
                ICON_SIZE_MEDIUM
597
            ).'</a>';
598
        echo '</div>';
599
600
        if ($survey_data['number_of_questions'] > 0) {
601
            $limitStatement = null;
602
            if (!$singlePage) {
603
                echo '<div id="question_report_questionnumbers" class="pagination">';
604
                if (0 != $currentQuestion) {
605
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
606
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset - 1).'">'
607
                        .get_lang('Previous question').'</a></li>';
608
                }
609
610
                for ($i = 1; $i <= $survey_data['number_of_questions']; $i++) {
611
                    if ($offset != $i - 1) {
612
                        echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
613
                            .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($i - 1).'">'.$i.'</a></li>';
614
                    } else {
615
                        echo '<li class="disabled"s><a href="#">'.$i.'</a></li>';
616
                    }
617
                }
618
                if ($currentQuestion < ($survey_data['number_of_questions'] - 1)) {
619
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
620
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset + 1).'">'
621
                        .get_lang('Next question').'</li></a>';
622
                }
623
                echo '</ul>';
624
                echo '</div>';
625
                $limitStatement = " LIMIT $offset, 1";
626
            }
627
628
            // Getting the question information
629
            $sql = "SELECT * FROM $table_survey_question
630
			        WHERE
631
			            c_id = $course_id AND
632
                        survey_id='".$surveyId."' AND
633
                        survey_question NOT LIKE '%{{%' AND
634
                        type <>'pagebreak'
635
                    ORDER BY sort ASC
636
                    $limitStatement";
637
            $result = Database::query($sql);
638
            while ($row = Database::fetch_array($result)) {
639
                $questions[$row['question_id']] = $row;
640
            }
641
        }
642
        foreach ($questions as $question) {
643
            $chartData = [];
644
            $options = [];
645
            $questionId = (int) $question['question_id'];
646
            echo '<div class="title-question">';
647
            echo strip_tags(isset($question['survey_question']) ? $question['survey_question'] : null);
648
            echo '</div>';
649
650
            if ('score' == $question['type']) {
651
                /** @todo This function should return the options as this is needed further in the code */
652
                $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...
653
            } elseif ('open' == $question['type'] || 'comment' == $question['type']) {
654
                /** @todo Also get the user who has answered this */
655
                $sql = "SELECT * FROM $table_survey_answer
656
                        WHERE
657
                            c_id = $course_id AND
658
                            survey_id= $surveyId AND
659
                            question_id = $questionId ";
660
                $result = Database::query($sql);
661
                while ($row = Database::fetch_array($result, 'ASSOC')) {
662
                    echo $row['option_id'].'<hr noshade="noshade" size="1" />';
663
                }
664
            } else {
665
                // Getting the options ORDER BY sort ASC
666
                $sql = "SELECT * FROM $table_survey_question_option
667
                        WHERE
668
                            c_id = $course_id AND
669
                            survey_id = $surveyId AND
670
                            question_id = $questionId
671
                        ORDER BY sort ASC";
672
                $result = Database::query($sql);
673
                while ($row = Database::fetch_array($result, 'ASSOC')) {
674
                    $options[$row['question_option_id']] = $row;
675
                }
676
                // Getting the answers
677
                $sql = "SELECT *, count(answer_id) as total
678
                        FROM $table_survey_answer
679
                        WHERE
680
                            c_id = $course_id AND
681
                            survey_id = $surveyId AND
682
                            question_id = $questionId
683
                        GROUP BY option_id, value";
684
                $result = Database::query($sql);
685
                $number_of_answers = [];
686
                $data = [];
687
                while ($row = Database::fetch_array($result, 'ASSOC')) {
688
                    if (!isset($number_of_answers[$row['question_id']])) {
689
                        $number_of_answers[$row['question_id']] = 0;
690
                    }
691
                    $number_of_answers[$row['question_id']] += $row['total'];
692
693
                    if ('multiplechoiceother' === $question['type']) {
694
                        $parts = ch_multiplechoiceother::decodeOptionValue($row['option_id']);
695
                        $row['option_id'] = $parts[0];
696
                    }
697
698
                    $data[$row['option_id']] = $row;
699
                }
700
701
                foreach ($options as $option) {
702
                    $optionText = strip_tags($option['option_text']);
703
                    $optionText = html_entity_decode($optionText);
704
                    $votes = 0;
705
                    if (isset($data[$option['question_option_id']]['total'])) {
706
                        $votes = $data[$option['question_option_id']]['total'];
707
                    }
708
                    array_push($chartData, ['option' => $optionText, 'votes' => $votes]);
709
                }
710
                $chartContainerId = 'chartContainer'.$question['question_id'];
711
                echo '<div id="'.$chartContainerId.'" class="col-md-12">';
712
713
                echo self::drawChart($chartData, false, $chartContainerId);
714
715
                // displaying the table: headers
716
                echo '<table class="display-survey table">';
717
                echo '	<tr>';
718
                echo '		<th>&nbsp;</th>';
719
                echo '		<th>'.get_lang('Absolute total').'</th>';
720
                echo '		<th>'.get_lang('Percentage').'</th>';
721
                echo '		<th>'.get_lang('Graphic').'</th>';
722
                echo '	<tr>';
723
724
                // Displaying the table: the content
725
                if (is_array($options)) {
726
                    foreach ($options as $key => &$value) {
727
                        if ('multiplechoiceother' === $question['type'] && 'other' === $value['option_text']) {
728
                            $value['option_text'] = get_lang('SurveyOtherAnswer');
729
                        }
730
731
                        $absolute_number = null;
732
                        if (isset($data[$value['question_option_id']])) {
733
                            $absolute_number = $data[$value['question_option_id']]['total'];
734
                        }
735
                        if ('percentage' == $question['type'] && empty($absolute_number)) {
736
                            continue;
737
                        }
738
                        $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...
739
                            ? $number_of_answers[$option['question_id']]
740
                            : 0;
741
                        if (0 == $number_of_answers[$option['question_id']]) {
742
                            $answers_number = 0;
743
                        } else {
744
                            $answers_number = $absolute_number / $number_of_answers[$option['question_id']] * 100;
745
                        }
746
                        echo '	<tr>';
747
                        echo '		<td class="center">'.$value['option_text'].'</td>';
748
                        echo '		<td class="center">';
749
                        if (0 != $absolute_number) {
750
                            echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
751
                                .'&survey_id='.$surveyId.'&question='.$offset.'&viewoption='
752
                                .$value['question_option_id'].'">'.$absolute_number.'</a>';
753
                        } else {
754
                            echo '0';
755
                        }
756
757
                        echo '      </td>';
758
                        echo '		<td class="center">'.round($answers_number, 2).' %</td>';
759
                        echo '		<td class="center">';
760
                        $size = $answers_number * 2;
761
                        if ($size > 0) {
762
                            echo '<div style="border:1px solid #264269; background-color:#aecaf4; height:10px; width:'
763
                                .$size.'px">&nbsp;</div>';
764
                        } else {
765
                            echo '<div style="text-align: left;">'.get_lang("No data available").'</div>';
766
                        }
767
                        echo ' </td>';
768
                        echo ' </tr>';
769
                    }
770
                }
771
772
                $optionResult = '';
773
                if (isset($option['question_id']) && isset($number_of_answers[$option['question_id']])) {
774
                    if (0 == $number_of_answers[$option['question_id']]) {
775
                        $optionResult = '0';
776
                    } else {
777
                        $optionResult = $number_of_answers[$option['question_id']];
778
                    }
779
                }
780
781
                // displaying the table: footer (totals)
782
                echo '	<tr>';
783
                echo '		<td class="total"><b>'.get_lang('Total').'</b></td>';
784
                echo '		<td class="total"><b>'.$optionResult.'</b></td>';
785
                echo '		<td class="total">&nbsp;</td>';
786
                echo '		<td class="total">&nbsp;</td>';
787
                echo '	</tr>';
788
                echo '</table>';
789
                echo '</div>';
790
            }
791
        }
792
793
        if (isset($_GET['viewoption'])) {
794
            echo '<div class="answered-people">';
795
            echo '<h4>'.get_lang('People who have chosen this answer').': '
796
                .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 642. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
797
798
            if (is_numeric($_GET['value'])) {
799
                $sql_restriction = "AND value='".Database::escape_string($_GET['value'])."'";
800
            }
801
802
            $sql = "SELECT user FROM $table_survey_answer
803
                    WHERE
804
                        c_id = $course_id AND
805
                        option_id = '".Database::escape_string($_GET['viewoption'])."'
806
                        $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...
807
            $result = Database::query($sql);
808
            echo '<ul>';
809
            while ($row = Database::fetch_array($result, 'ASSOC')) {
810
                $user_info = api_get_user_info($row['user']);
811
                echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
812
                    .$surveyId.'&user='.$row['user'].'">'
813
                    .$user_info['complete_name_with_username']
814
                    .'</a></li>';
815
            }
816
            echo '</ul>';
817
            echo '</div>';
818
        }
819
    }
820
821
    /**
822
     * Display score data about a survey question.
823
     *
824
     * @param    array    Question info
825
     * @param    int    The offset of results shown
826
     */
827
    public static function display_question_report_score($survey_data, $question, $offset)
828
    {
829
        // Database table definitions
830
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
831
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
832
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
833
        $course_id = api_get_course_int_id();
834
        $surveyId = $survey_data['survey_id'];
835
836
        // Getting the options
837
        $sql = "SELECT * FROM $table_survey_question_option
838
                WHERE
839
                    c_id = $course_id AND
840
                    survey_id= $surveyId AND
841
                    question_id = '".intval($question['question_id'])."'
842
                ORDER BY sort ASC";
843
        $result = Database::query($sql);
844
        while ($row = Database::fetch_array($result)) {
845
            $options[$row['question_option_id']] = $row;
846
        }
847
848
        // Getting the answers
849
        $sql = "SELECT *, count(answer_id) as total
850
                FROM $table_survey_answer
851
                WHERE
852
                   c_id = $course_id AND
853
                   survey_id= $surveyId AND
854
                   question_id = '".Database::escape_string($question['question_id'])."'
855
                GROUP BY option_id, value";
856
        $result = Database::query($sql);
857
        $number_of_answers = 0;
858
        while ($row = Database::fetch_array($result)) {
859
            $number_of_answers += $row['total'];
860
            $data[$row['option_id']][$row['value']] = $row;
861
        }
862
863
        $chartData = [];
864
        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...
865
            $optionText = strip_tags($option['option_text']);
866
            $optionText = html_entity_decode($optionText);
867
            for ($i = 1; $i <= $question['max_value']; $i++) {
868
                $votes = null;
869
                if (isset($data[$option['question_option_id']][$i])) {
870
                    $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...
871
                }
872
873
                if (empty($votes)) {
874
                    $votes = '0';
875
                }
876
                array_push(
877
                    $chartData,
878
                    [
879
                        'serie' => $optionText,
880
                        'option' => $i,
881
                        'votes' => $votes,
882
                    ]
883
                );
884
            }
885
        }
886
        echo '<div id="chartContainer" class="col-md-12">';
887
        echo self::drawChart($chartData, true);
888
        echo '</div>';
889
890
        // Displaying the table: headers
891
        echo '<table class="table">';
892
        echo '	<tr>';
893
        echo '		<th>&nbsp;</th>';
894
        echo '		<th>'.get_lang('Score').'</th>';
895
        echo '		<th>'.get_lang('Absolute total').'</th>';
896
        echo '		<th>'.get_lang('Percentage').'</th>';
897
        echo '		<th>'.get_lang('Graphic').'</th>';
898
        echo '	<tr>';
899
        // Displaying the table: the content
900
        foreach ($options as $key => &$value) {
901
            for ($i = 1; $i <= $question['max_value']; $i++) {
902
                $absolute_number = null;
903
                if (isset($data[$value['question_option_id']][$i])) {
904
                    $absolute_number = $data[$value['question_option_id']][$i]['total'];
905
                }
906
907
                echo '	<tr>';
908
                echo '		<td>'.$value['option_text'].'</td>';
909
                echo '		<td>'.$i.'</td>';
910
                echo '		<td><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
911
                    .'&survey_id='.$surveyId.'&question='.Security::remove_XSS($offset)
912
                    .'&viewoption='.$value['question_option_id'].'&value='.$i.'">'.$absolute_number.'</a></td>';
913
                echo '		<td>'.round($absolute_number / $number_of_answers * 100, 2).' %</td>';
914
                echo '		<td>';
915
                $size = ($absolute_number / $number_of_answers * 100 * 2);
916
                if ($size > 0) {
917
                    echo '<div style="border:1px solid #264269; background-color:#aecaf4; height:10px; width:'.$size.'px">&nbsp;</div>';
918
                }
919
                echo '		</td>';
920
                echo '	</tr>';
921
            }
922
        }
923
        // Displaying the table: footer (totals)
924
        echo '	<tr>';
925
        echo '		<td style="border-top:1px solid black"><b>'.get_lang('Total').'</b></td>';
926
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
927
        echo '		<td style="border-top:1px solid black"><b>'.$number_of_answers.'</b></td>';
928
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
929
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
930
        echo '	</tr>';
931
        echo '</table>';
932
    }
933
934
    /**
935
     * This functions displays the complete reporting.
936
     *
937
     * @param array $survey_data
938
     * @param int   $userId
939
     * @param bool  $addActionBar
940
     * @param bool  $addFilters
941
     * @param bool  $addExtraFields
942
     *
943
     * @return string
944
     */
945
    public static function displayCompleteReport(
946
        $survey_data,
947
        $userId = 0,
948
        $addActionBar = true,
949
        $addFilters = true,
950
        $addExtraFields = true
951
    ) {
952
        // Database table definitions
953
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
954
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
955
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
956
957
        $surveyId = (int) $survey_data['survey_id'];
958
        $course_id = (int) $survey_data['c_id'];
959
960
        if (empty($surveyId) || empty($course_id)) {
961
            return '';
962
        }
963
964
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
965
        $content = '';
966
        if ($addActionBar) {
967
            $content .= '<div class="actions">';
968
            $content .= '<a
969
                href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
970
                .Display::return_icon(
971
                    'back.png',
972
                    get_lang('Back to').' '.get_lang('Reporting overview'),
973
                    [],
974
                    ICON_SIZE_MEDIUM
975
                )
976
                .'</a>';
977
            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
978
                .Display::return_icon('export_csv.png', get_lang('CSV export'), '', ICON_SIZE_MEDIUM).'</a>';
979
            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
980
                .Display::return_icon('export_excel.png', get_lang('Excel export'), '', ICON_SIZE_MEDIUM).'</a>';
981
            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1c.submit();">'
982
                .Display::return_icon('export_compact_csv.png', get_lang('ExportAsCompactCSV'), '', ICON_SIZE_MEDIUM).'</a>';
983
            $content .= '</div>';
984
985
            // The form
986
            $content .= '<form id="form1a" name="form1a" method="post" action="'.api_get_self(
987
                ).'?action='.$action.'&survey_id='
988
                .$surveyId.'&'.api_get_cidreq().'">';
989
            $content .= '<input type="hidden" name="export_report" value="export_report">';
990
            $content .= '<input type="hidden" name="export_format" value="csv">';
991
            $content .= '</form>';
992
            $content .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self(
993
                ).'?action='.$action.'&survey_id='
994
                .$surveyId.'&'.api_get_cidreq().'">';
995
            $content .= '<input type="hidden" name="export_report" value="export_report">';
996
            $content .= '<input type="hidden" name="export_format" value="xls">';
997
            $content .= '</form>';
998
            $content .= '<form id="form1c" name="form1c" method="post" action="'.api_get_self(
999
                ).'?action='.$action.'&survey_id='
1000
                .$surveyId.'&'.api_get_cidreq().'">';
1001
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1002
            $content .= '<input type="hidden" name="export_format" value="csv-compact">';
1003
            $content .= '</form>';
1004
        }
1005
1006
        $content .= '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
1007
            .$surveyId.'&'.api_get_cidreq().'">';
1008
1009
        // The table
1010
        $content .= '<br /><table class="data_table" border="1">';
1011
        // Getting the number of options per question
1012
        $content .= '	<tr>';
1013
        $content .= '		<th>';
1014
1015
        if ($addFilters) {
1016
            if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1017
                (isset($_POST['export_report']) && $_POST['export_report'])
1018
            ) {
1019
                $content .= '<button class="cancel"
1020
                                type="submit"
1021
                                name="reset_question_filter" value="'.get_lang('Reset filter').'">'.
1022
                                get_lang('Reset filter').'</button>';
1023
            }
1024
            $content .= '<button
1025
                            class = "save"
1026
                            type="submit" name="submit_question_filter" value="'.get_lang('Filter').'">'.
1027
                            get_lang('Filter').'</button>';
1028
            $content .= '</th>';
1029
        }
1030
1031
        $display_extra_user_fields = false;
1032
        if ($addExtraFields) {
1033
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1034
                    isset($_POST['export_report']) && $_POST['export_report']) ||
1035
                !empty($_POST['fields_filter'])
1036
            ) {
1037
                // Show user fields section with a big th colspan that spans over all fields
1038
                $extra_user_fields = UserManager::get_extra_fields(
1039
                    0,
1040
                    0,
1041
                    5,
1042
                    'ASC',
1043
                    false,
1044
                    true
1045
                );
1046
                $num = count($extra_user_fields);
1047
                if ($num > 0) {
1048
                    $content .= '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
1049
                    $content .= '<label>';
1050
                    if ($addFilters) {
1051
                        $content .= '<input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
1052
                    }
1053
                    $content .= get_lang('Profile attributes');
1054
                    $content .= '</label>';
1055
                    $content .= '</th>';
1056
                    $display_extra_user_fields = true;
1057
                }
1058
            }
1059
        }
1060
1061
        $sql = "SELECT
1062
                  q.question_id,
1063
                  q.type,
1064
                  q.survey_question,
1065
                  count(o.question_option_id) as number_of_options
1066
				FROM $table_survey_question q
1067
				LEFT JOIN $table_survey_question_option o
1068
				ON q.question_id = o.question_id AND q.c_id = o.c_id
1069
				WHERE
1070
				    survey_question NOT LIKE '%{{%' AND
1071
				    q.survey_id = '".$surveyId."' AND
1072
				    q.c_id = $course_id
1073
				GROUP BY q.question_id
1074
				ORDER BY q.sort ASC";
1075
        $result = Database::query($sql);
1076
        $questions = [];
1077
        while ($row = Database::fetch_array($result)) {
1078
            // We show the questions if
1079
            // 1. there is no question filter and the export button has not been clicked
1080
            // 2. there is a quesiton filter but the question is selected for display
1081
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1082
                (is_array($_POST['questions_filter']) &&
1083
                in_array($row['question_id'], $_POST['questions_filter']))
1084
            ) {
1085
                // We do not show comment and pagebreak question types
1086
                if ('pagebreak' != $row['type']) {
1087
                    $content .= ' <th';
1088
                    if ($row['number_of_options'] > 0 && 'percentage' != $row['type']) {
1089
                        $content .= ' colspan="'.$row['number_of_options'].'"';
1090
                    }
1091
                    $content .= '>';
1092
                    $content .= '<label>';
1093
                    if ($addFilters) {
1094
                        $content .= '<input
1095
                                type="checkbox"
1096
                                name="questions_filter[]" value="'.$row['question_id'].'" checked="checked"/>';
1097
                    }
1098
                    $content .= $row['survey_question'];
1099
                    $content .= '</label>';
1100
                    $content .= '</th>';
1101
                }
1102
                // No column at all if it's not a question
1103
            }
1104
            $questions[$row['question_id']] = $row;
1105
        }
1106
        $content .= '	</tr>';
1107
1108
        // Getting all the questions and options
1109
        $content .= '	<tr>';
1110
        $content .= '		<th>&nbsp;</th>'; // the user column
1111
1112
        if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1113
            isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter'])
1114
        ) {
1115
            if ($addExtraFields) {
1116
                // show the fields names for user fields
1117
                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...
1118
                    $content .= '<th>'.$field[3].'</th>';
1119
                }
1120
            }
1121
        }
1122
1123
        // cells with option (none for open question)
1124
        $sql = "SELECT
1125
                    sq.question_id,
1126
                    sq.survey_id,
1127
                    sq.survey_question,
1128
                    sq.display,
1129
                    sq.sort,
1130
                    sq.type,
1131
                    sqo.question_option_id,
1132
                    sqo.option_text,
1133
                    sqo.sort as option_sort
1134
				FROM $table_survey_question sq
1135
				LEFT JOIN $table_survey_question_option sqo
1136
				ON sq.question_id = sqo.question_id AND sq.c_id = sqo.c_id
1137
				WHERE
1138
				    survey_question NOT LIKE '%{{%' AND
1139
				    sq.survey_id = '".$surveyId."' AND
1140
                    sq.c_id = $course_id
1141
				ORDER BY sq.sort ASC, sqo.sort ASC";
1142
        $result = Database::query($sql);
1143
1144
        $display_percentage_header = 1;
1145
        $possible_answers = [];
1146
        // in order to display only once the cell option (and not 100 times)
1147
        while ($row = Database::fetch_array($result)) {
1148
            // We show the options if
1149
            // 1. there is no question filter and the export button has not been clicked
1150
            // 2. there is a question filter but the question is selected for display
1151
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1152
                (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']))
1153
            ) {
1154
                // we do not show comment and pagebreak question types
1155
                if ('open' == $row['type'] || 'comment' == $row['type']) {
1156
                    $content .= '<th>&nbsp;-&nbsp;</th>';
1157
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1158
                    $display_percentage_header = 1;
1159
                } elseif ('percentage' == $row['type'] && $display_percentage_header) {
1160
                    $content .= '<th>&nbsp;%&nbsp;</th>';
1161
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1162
                    $display_percentage_header = 0;
1163
                } elseif ('percentage' == $row['type']) {
1164
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1165
                } elseif ('pagebreak' != $row['type'] && 'percentage' != $row['type']) {
1166
                    $content .= '<th>';
1167
                    $content .= $row['option_text'];
1168
                    $content .= '</th>';
1169
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1170
                    $display_percentage_header = 1;
1171
                }
1172
            }
1173
        }
1174
1175
        $content .= '	</tr>';
1176
1177
        $userCondition = '';
1178
        if (!empty($userId)) {
1179
            $userId = (int) $userId;
1180
            $userCondition = " AND user = $userId ";
1181
        }
1182
1183
        // Getting all the answers of the users
1184
        $old_user = '';
1185
        $answers_of_user = [];
1186
        $sql = "SELECT * FROM $table_survey_answer
1187
                WHERE
1188
                    c_id = $course_id AND
1189
                    survey_id = $surveyId
1190
                    $userCondition
1191
                ORDER BY answer_id, user ASC";
1192
        $result = Database::query($sql);
1193
        $i = 1;
1194
        while ($row = Database::fetch_array($result)) {
1195
            if ($old_user != $row['user'] && '' != $old_user) {
1196
                $userParam = $old_user;
1197
                if (0 != $survey_data['anonymous']) {
1198
                    $userParam = $i;
1199
                    $i++;
1200
                }
1201
                $content .= self::display_complete_report_row(
1202
                    $survey_data,
1203
                    $possible_answers,
1204
                    $answers_of_user,
1205
                    $userParam,
1206
                    $questions,
1207
                    $display_extra_user_fields
1208
                );
1209
                $answers_of_user = [];
1210
            }
1211
            if (isset($questions[$row['question_id']]) &&
1212
                'open' != $questions[$row['question_id']]['type'] &&
1213
                'comment' != $questions[$row['question_id']]['type']
1214
            ) {
1215
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1216
            } else {
1217
                $answers_of_user[$row['question_id']][0] = $row;
1218
            }
1219
            $old_user = $row['user'];
1220
        }
1221
1222
        $userParam = $old_user;
1223
        if (0 != $survey_data['anonymous']) {
1224
            $userParam = $i;
1225
            $i++;
1226
        }
1227
1228
        $content .= self::display_complete_report_row(
1229
            $survey_data,
1230
            $possible_answers,
1231
            $answers_of_user,
1232
            $userParam,
1233
            $questions,
1234
            $display_extra_user_fields
1235
        );
1236
1237
        // This is to display the last user
1238
        $content .= '</table>';
1239
        $content .= '</form>';
1240
1241
        return $content;
1242
    }
1243
1244
    /**
1245
     * Return user answers in a row.
1246
     *
1247
     * @param      $survey_data
1248
     * @param      $possible_options
1249
     * @param      $answers_of_user
1250
     * @param      $user
1251
     * @param      $questions
1252
     * @param bool $display_extra_user_fields
1253
     *
1254
     * @return string
1255
     */
1256
    public static function display_complete_report_row(
1257
        $survey_data,
1258
        $possible_options,
1259
        $answers_of_user,
1260
        $user,
1261
        $questions,
1262
        $display_extra_user_fields = false
1263
    ) {
1264
        $user = Security::remove_XSS($user);
1265
        $surveyId = (int) $survey_data['survey_id'];
1266
1267
        if (empty($surveyId)) {
1268
            return '';
1269
        }
1270
1271
        $content = '<tr>';
1272
        $url = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
1273
        if (0 == $survey_data['anonymous']) {
1274
            if (0 !== intval($user)) {
1275
                $userInfo = api_get_user_info($user);
1276
                $user_displayed = '-';
1277
                if (!empty($userInfo)) {
1278
                    $user_displayed = $userInfo['complete_name_with_username'];
1279
                }
1280
1281
                $content .= '<th>
1282
                    <a href="'.$url.'&action=userreport&user='.$user.'">'
1283
                    .$user_displayed.'</a>
1284
                    </th>'; // the user column
1285
            } else {
1286
                $content .= '<th>'.$user.'</th>'; // the user column
1287
            }
1288
        } else {
1289
            $content .= '<th>'.get_lang('Anonymous').' '.$user.'</th>';
1290
        }
1291
1292
        if ($display_extra_user_fields) {
1293
            // Show user fields data, if any, for this user
1294
            $user_fields_values = UserManager::get_extra_user_data(
1295
                $user,
1296
                false,
1297
                false,
1298
                false,
1299
                true
1300
            );
1301
            foreach ($user_fields_values as &$value) {
1302
                $content .= '<td align="center">'.$value.'</td>';
1303
            }
1304
        }
1305
1306
        if (is_array($possible_options)) {
1307
            foreach ($possible_options as $question_id => &$possible_option) {
1308
                if ('open' == $questions[$question_id]['type'] || 'comment' == $questions[$question_id]['type']) {
1309
                    $content .= '<td align="center">';
1310
                    if (isset($answers_of_user[$question_id]) && isset($answers_of_user[$question_id]['0'])) {
1311
                        $content .= $answers_of_user[$question_id]['0']['option_id'];
1312
                    }
1313
                    $content .= '</td>';
1314
                } else {
1315
                    foreach ($possible_option as $option_id => $value) {
1316
                        if ($questions[$question_id]['type'] === 'multiplechoiceother') {
1317
                            foreach ($answers_of_user[$question_id] as $key => $newValue) {
1318
                                $parts = ch_multiplechoiceother::decodeOptionValue($key);
1319
                                if (isset($parts[0])) {
1320
                                    $data = $answers_of_user[$question_id][$key];
1321
                                    unset($answers_of_user[$question_id][$key]);
1322
                                    $newKey = $parts[0];
1323
                                    $answers_of_user[$question_id][$newKey] = $data;
1324
                                }
1325
                            }
1326
                        }
1327
                        if ($questions[$question_id]['type'] === 'percentage') {
1328
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1329
                                $content .= "<td align='center'>";
1330
                                $content .= $answers_of_user[$question_id][$option_id]['value'];
1331
                                $content .= "</td>";
1332
                            }
1333
                        } else {
1334
                            $content .= '<td align="center">';
1335
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1336
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1337
                                    $content .= $answers_of_user[$question_id][$option_id]['value'];
1338
                                } else {
1339
                                    $content .= 'v';
1340
                                }
1341
                            }
1342
                        }
1343
                    }
1344
                }
1345
            }
1346
        }
1347
1348
        $content .= '</tr>';
1349
1350
        return $content;
1351
    }
1352
1353
    /**
1354
     * Quite similar to display_complete_report(), returns an HTML string
1355
     * that can be used in a csv file.
1356
     *
1357
     * @todo consider merging this function with display_complete_report
1358
     *
1359
     * @return string The contents of a csv file
1360
     *
1361
     * @author Patrick Cool <[email protected]>, Ghent University
1362
     *
1363
     * @version February 2007
1364
     */
1365
    public static function export_complete_report($survey_data, $user_id = 0, $compact = false)
1366
    {
1367
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
1368
1369
        if (empty($surveyId)) {
1370
            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...
1371
        }
1372
1373
        $course = api_get_course_info();
1374
        $course_id = $course['real_id'];
1375
1376
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1377
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1378
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1379
1380
        $translate = false;
1381
        if (api_get_configuration_value('translate_html') == true) {
1382
            $translate = true;
1383
        }
1384
1385
        // The first column
1386
        $return = ';';
1387
1388
        // Show extra fields blank space (enough for extra fields on next line)
1389
        $extra_user_fields = UserManager::get_extra_fields(
1390
            0,
1391
            0,
1392
            5,
1393
            'ASC',
1394
            false,
1395
            true
1396
        );
1397
1398
        $num = count($extra_user_fields);
1399
        $return .= str_repeat(';', $num);
1400
1401
        $sql = "SELECT
1402
                    questions.question_id,
1403
                    questions.type,
1404
                    questions.survey_question,
1405
                    count(options.question_option_id) as number_of_options
1406
				FROM $table_survey_question questions
1407
                LEFT JOIN $table_survey_question_option options
1408
				ON
1409
				  questions.question_id = options.question_id AND
1410
				  options.c_id = questions.c_id
1411
				WHERE
1412
				    survey_question NOT LIKE '%{{%' AND
1413
				    questions.type <> 'pagebreak' AND
1414
				    questions.survey_id = $surveyId AND
1415
                    questions.c_id = $course_id
1416
				GROUP BY questions.question_id
1417
				ORDER BY questions.sort ASC";
1418
1419
        $result = Database::query($sql);
1420
        while ($row = Database::fetch_array($result)) {
1421
            if ($translate) {
1422
                $row['survey_question'] = api_get_filtered_multilingual_HTML_string($row['survey_question'], $course['language']);
0 ignored issues
show
Bug introduced by
The function api_get_filtered_multilingual_HTML_string was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1422
                $row['survey_question'] = /** @scrutinizer ignore-call */ api_get_filtered_multilingual_HTML_string($row['survey_question'], $course['language']);
Loading history...
1423
            }
1424
            // We show the questions if
1425
            // 1. there is no question filter and the export button has not been clicked
1426
            // 2. there is a quesiton filter but the question is selected for display
1427
            if (!(isset($_POST['submit_question_filter'])) ||
1428
                (isset($_POST['submit_question_filter']) &&
1429
                    is_array($_POST['questions_filter']) &&
1430
                    in_array($row['question_id'], $_POST['questions_filter']))
1431
            ) {
1432
                if ($row['number_of_options'] == 0 or $compact) {
1433
                    $return .= str_replace(
1434
                        "\r\n",
1435
                        '  ',
1436
                        api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1437
                    )
1438
                    .';';
1439
                } else {
1440
                    for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1441
                        $return .= str_replace(
1442
                            "\r\n",
1443
                            '  ',
1444
                            api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1445
                        )
1446
                        .';';
1447
                    }
1448
                }
1449
            }
1450
        }
1451
1452
        $return .= "\n";
1453
        // Getting all the questions and options
1454
        $return .= ';';
1455
        // Show the fields names for user fields
1456
        if (!empty($extra_user_fields)) {
1457
            foreach ($extra_user_fields as &$field) {
1458
                if ($translate) {
1459
                    $field[3] = api_get_filtered_multilingual_HTML_string($field[3], $course['language']);
1460
                }
1461
                $return .= '"'
1462
                    .str_replace(
1463
                        "\r\n",
1464
                        '  ',
1465
                        api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES)
1466
                    )
1467
                    .'";';
1468
            }
1469
        }
1470
1471
        $sql = "SELECT DISTINCT
1472
		            survey_question.question_id,
1473
		            survey_question.survey_id,
1474
		            survey_question.survey_question,
1475
		            survey_question.display,
1476
		            survey_question.sort,
1477
		            survey_question.type,
1478
                    survey_question_option.question_option_id,
1479
                    survey_question_option.option_text,
1480
                    survey_question_option.sort as option_sort
1481
				FROM $table_survey_question survey_question
1482
				LEFT JOIN $table_survey_question_option survey_question_option
1483
				ON
1484
				    survey_question.question_id = survey_question_option.question_id AND
1485
				    survey_question_option.c_id = survey_question.c_id
1486
				WHERE
1487
				    survey_question NOT LIKE '%{{%' AND
1488
				    survey_question.type <> 'pagebreak' AND
1489
				    survey_question.survey_id = $surveyId AND
1490
				    survey_question.c_id = $course_id
1491
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1492
        $result = Database::query($sql);
1493
        $possible_answers = [];
1494
        $possible_answers_type = [];
1495
        while ($row = Database::fetch_array($result)) {
1496
            // We show the options if
1497
            // 1. there is no question filter and the export button has not been clicked
1498
            // 2. there is a question filter but the question is selected for display
1499
            if ($translate) {
1500
                $row['option_text'] = api_get_filtered_multilingual_HTML_string($row['option_text'], $course['language']);
1501
            }
1502
            if (!(isset($_POST['submit_question_filter'])) || (
1503
                is_array($_POST['questions_filter']) &&
1504
                in_array($row['question_id'], $_POST['questions_filter'])
1505
            )
1506
            ) {
1507
                $row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']);
1508
                if (!$compact) {
1509
                    $return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';';
1510
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1511
                } else {
1512
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['option_text'];
1513
                }
1514
                $possible_answers_type[$row['question_id']] = $row['type'];
1515
            }
1516
        }
1517
1518
        $return .= "\n";
1519
1520
        // Getting all the answers of the users
1521
        $old_user = '';
1522
        $answers_of_user = [];
1523
        $sql = "SELECT * FROM $table_survey_answer
1524
		        WHERE
1525
		          c_id = $course_id AND
1526
		          survey_id = $surveyId
1527
		          ";
1528
        if ($user_id != 0) {
1529
            $user_id = intval($user_id);
1530
            $sql .= " AND user = $user_id ";
1531
        }
1532
        $sql .= ' ORDER BY user ASC ';
1533
1534
        $questionIdList = array_keys($possible_answers_type);
1535
        $open_question_iterator = 1;
1536
        $result = Database::query($sql);
1537
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1538
            if (!in_array($row['question_id'], $questionIdList)) {
1539
                continue;
1540
            }
1541
            if ($old_user != $row['user'] && '' != $old_user) {
1542
                $return .= self::export_complete_report_row(
1543
                    $survey_data,
1544
                    $possible_answers,
1545
                    $answers_of_user,
1546
                    $old_user,
1547
                    true,
1548
                    $compact
1549
                );
1550
                $answers_of_user = [];
1551
            }
1552
1553
            if ('open' == $possible_answers_type[$row['question_id']] ||
1554
                'comment' == $possible_answers_type[$row['question_id']]
1555
            ) {
1556
                $temp_id = 'open'.$open_question_iterator;
1557
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1558
                $open_question_iterator++;
1559
            } else {
1560
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1561
            }
1562
            $old_user = $row['user'];
1563
        }
1564
1565
        // This is to display the last user
1566
        $return .= self::export_complete_report_row(
1567
            $survey_data,
1568
            $possible_answers,
1569
            $answers_of_user,
1570
            $old_user,
1571
            true,
1572
            $compact
1573
        );
1574
1575
        return $return;
1576
    }
1577
1578
    /**
1579
     * Add a line to the csv file.
1580
     *
1581
     * @param array Possible answers
1582
     * @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...
1583
     * @param mixed User ID or user details as string - Used as a string in the result string
1584
     * @param bool Whether to display user fields or not
1585
     *
1586
     * @return string One line of the csv file
1587
     *
1588
     * @author Patrick Cool <[email protected]>, Ghent University
1589
     *
1590
     * @version February 2007
1591
     */
1592
    public static function export_complete_report_row(
1593
        $survey_data,
1594
        $possible_options,
1595
        $answers_of_user,
1596
        $user,
1597
        $display_extra_user_fields = false,
1598
        $compact = false
1599
    ) {
1600
        $return = '';
1601
        if (0 == $survey_data['anonymous']) {
1602
            if (0 !== intval($user)) {
1603
                $userInfo = api_get_user_info($user);
1604
                if (!empty($userInfo)) {
1605
                    $user_displayed = $userInfo['complete_name_with_username'];
1606
                } else {
1607
                    $user_displayed = '-';
1608
                }
1609
                $return .= $user_displayed.';';
1610
            } else {
1611
                $return .= $user.';';
1612
            }
1613
        } else {
1614
            $return .= '-;'; // The user column
1615
        }
1616
1617
        if ($display_extra_user_fields) {
1618
            // Show user fields data, if any, for this user
1619
            $user_fields_values = UserManager::get_extra_user_data(
1620
                $user,
1621
                false,
1622
                false,
1623
                false,
1624
                true
1625
            );
1626
            foreach ($user_fields_values as &$value) {
1627
                $return .= '"'.str_replace('"', '""', api_html_entity_decode(strip_tags($value), ENT_QUOTES)).'";';
1628
            }
1629
        }
1630
1631
1632
        if (is_array($possible_options)) {
1633
            foreach ($possible_options as $question_id => $possible_option) {
1634
                if (is_array($possible_option) && count($possible_option) > 0) {
1635
                    foreach ($possible_option as $option_id => &$value) {
1636
                        // For each option of this question, look if it matches the user's answer
1637
                        $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];
1638
                        $key = array_keys($my_answer_of_user);
1639
                        if (isset($key[0]) && substr($key[0], 0, 4) == 'open') {
1640
                            // If this is an open type question (type starts by 'open'), take whatever answer is given
1641
                            $return .= '"'.
1642
                                str_replace(
1643
                                    '"',
1644
                                    '""',
1645
                                    api_html_entity_decode(
1646
                                        strip_tags(
1647
                                            $answers_of_user[$question_id][$key[0]]['option_id']
1648
                                        ),
1649
                                        ENT_QUOTES
1650
                                    )
1651
                                ).
1652
                                '";';
1653
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1654
                            //$return .= 'v';
1655
                            if ($compact) {
1656
                                // If we asked for a compact view, show only one column for the question
1657
                                // and fill it with the text of the selected option (i.e. "Yes") instead of an ID
1658
                                if ($answers_of_user[$question_id][$option_id]['value'] != 0) {
1659
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1660
                            } else {
1661
                                    $return .= '"'.
1662
                                        str_replace(
1663
                                            '"',
1664
                                            '""',
1665
                                            api_html_entity_decode(
1666
                                                strip_tags(
1667
                                                    $possible_option[$option_id]
1668
                                                ),
1669
                                                ENT_QUOTES
1670
                                            )
1671
                                        ).
1672
                                        '";';
1673
                            }
1674
                            } else {
1675
                                // If we don't want a compact view, show one column per possible option and mark a 'v'
1676
                                // or the defined value in the corresponding column if the user selected it
1677
                                if ($answers_of_user[$question_id][$option_id]['value'] != 0) {
1678
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1679
                                } else {
1680
                                    $return .= 'v;';
1681
                        }
1682
                            }
1683
                        } else {
1684
                            if (!$compact) {
1685
                        $return .= ';';
1686
                            }
1687
                        }
1688
                    }
1689
                }
1690
            }
1691
        }
1692
        $return .= "\n";
1693
1694
        return $return;
1695
    }
1696
1697
    /**
1698
     * Quite similar to display_complete_report(), returns an HTML string
1699
     * that can be used in a csv file.
1700
     *
1701
     * @todo consider merging this function with display_complete_report
1702
     *
1703
     * @return string The contents of a csv file
1704
     *
1705
     * @author Patrick Cool <[email protected]>, Ghent University
1706
     *
1707
     * @version February 2007
1708
     */
1709
    public static function export_complete_report_xls($survey_data, $filename, $user_id = 0, $returnFile = false)
1710
    {
1711
        $course_id = api_get_course_int_id();
1712
        $user_id = (int) $user_id;
1713
        $surveyId = $survey_data['survey_id'];
1714
1715
        if (empty($course_id) || empty($surveyId)) {
1716
            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...
1717
        }
1718
1719
        // Show extra fields blank space (enough for extra fields on next line)
1720
        // Show user fields section with a big th colspan that spans over all fields
1721
        $extra_user_fields = UserManager::get_extra_fields(
1722
            0,
1723
            0,
1724
            5,
1725
            'ASC',
1726
            false,
1727
            true
1728
        );
1729
        $list = [];
1730
        $num = count($extra_user_fields);
1731
        for ($i = 0; $i < $num; $i++) {
1732
            $list[0][] = '';
1733
        }
1734
1735
        $display_extra_user_fields = true;
1736
1737
        // Database table definitions
1738
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1739
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1740
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1741
1742
        // First line (questions)
1743
        $sql = "SELECT
1744
                    questions.question_id,
1745
                    questions.type,
1746
                    questions.survey_question,
1747
                    count(options.question_option_id) as number_of_options
1748
				FROM $table_survey_question questions
1749
				LEFT JOIN $table_survey_question_option options
1750
                ON
1751
                  questions.question_id = options.question_id AND
1752
                  options.c_id = questions.c_id
1753
				WHERE
1754
				    survey_question NOT LIKE '%{{%' AND
1755
				    questions.type <> 'pagebreak' AND
1756
				    questions.survey_id = $surveyId AND
1757
				    questions.c_id = $course_id
1758
				GROUP BY questions.question_id
1759
				ORDER BY questions.sort ASC";
1760
        $result = Database::query($sql);
1761
        $line = 1;
1762
        $column = 1;
1763
        while ($row = Database::fetch_array($result)) {
1764
            // We show the questions if
1765
            // 1. there is no question filter and the export button has not been clicked
1766
            // 2. there is a quesiton filter but the question is selected for display
1767
            if (!(isset($_POST['submit_question_filter'])) ||
1768
                (isset($_POST['submit_question_filter']) && is_array($_POST['questions_filter']) &&
1769
                in_array($row['question_id'], $_POST['questions_filter']))
1770
            ) {
1771
                // We do not show comment and pagebreak question types
1772
                if ('pagebreak' != $row['type']) {
1773
                    if (0 == $row['number_of_options'] && ('open' == $row['type'] || 'comment' == $row['type'])) {
1774
                        $list[$line][$column] = api_html_entity_decode(
1775
                            strip_tags($row['survey_question']),
1776
                            ENT_QUOTES
1777
                        );
1778
                        $column++;
1779
                    } else {
1780
                        for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1781
                            $list[$line][$column] = api_html_entity_decode(
1782
                                strip_tags($row['survey_question']),
1783
                                ENT_QUOTES
1784
                            );
1785
                            $column++;
1786
                        }
1787
                    }
1788
                }
1789
            }
1790
        }
1791
1792
        $line++;
1793
        $column = 1;
1794
        // Show extra field values
1795
        if ($display_extra_user_fields) {
1796
            // Show the fields names for user fields
1797
            foreach ($extra_user_fields as &$field) {
1798
                $list[$line][$column] = api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES);
1799
                $column++;
1800
            }
1801
        }
1802
1803
        // Getting all the questions and options (second line)
1804
        $sql = "SELECT
1805
                    survey_question.question_id,
1806
                    survey_question.survey_id,
1807
                    survey_question.survey_question,
1808
                    survey_question.display,
1809
                    survey_question.sort,
1810
                    survey_question.type,
1811
                    survey_question_option.question_option_id,
1812
                    survey_question_option.option_text,
1813
                    survey_question_option.sort as option_sort
1814
				FROM $table_survey_question survey_question
1815
				LEFT JOIN $table_survey_question_option survey_question_option
1816
				ON
1817
				    survey_question.question_id = survey_question_option.question_id AND
1818
				    survey_question_option.c_id = survey_question.c_id
1819
				WHERE
1820
				    survey_question NOT LIKE '%{{%' AND
1821
				    survey_question.type <> 'pagebreak' AND
1822
				    survey_question.survey_id = $surveyId AND
1823
				    survey_question.c_id = $course_id
1824
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1825
        $result = Database::query($sql);
1826
        $possible_answers = [];
1827
        $possible_answers_type = [];
1828
        while ($row = Database::fetch_array($result)) {
1829
            // We show the options if
1830
            // 1. there is no question filter and the export button has not been clicked
1831
            // 2. there is a quesiton filter but the question is selected for display
1832
            if (!isset($_POST['submit_question_filter']) ||
1833
                (isset($_POST['questions_filter']) && is_array($_POST['questions_filter']) &&
1834
                in_array($row['question_id'], $_POST['questions_filter']))
1835
            ) {
1836
                // We do not show comment and pagebreak question types
1837
                if ('pagebreak' != $row['type']) {
1838
                    $list[$line][$column] = api_html_entity_decode(
1839
                        strip_tags($row['option_text']),
1840
                        ENT_QUOTES
1841
                    );
1842
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1843
                    $possible_answers_type[$row['question_id']] = $row['type'];
1844
                    $column++;
1845
                }
1846
            }
1847
        }
1848
1849
        // Getting all the answers of the users
1850
        $line++;
1851
        $column = 0;
1852
        $old_user = '';
1853
        $answers_of_user = [];
1854
        $sql = "SELECT * FROM $table_survey_answer
1855
                WHERE c_id = $course_id AND survey_id = $surveyId";
1856
        if (0 != $user_id) {
1857
            $sql .= " AND user='".$user_id."' ";
1858
        }
1859
        $sql .= ' ORDER BY user ASC';
1860
1861
        $open_question_iterator = 1;
1862
        $result = Database::query($sql);
1863
        while ($row = Database::fetch_array($result)) {
1864
            if ($old_user != $row['user'] && '' != $old_user) {
1865
                $return = self::export_complete_report_row_xls(
1866
                    $survey_data,
1867
                    $possible_answers,
1868
                    $answers_of_user,
1869
                    $old_user,
1870
                    true
1871
                );
1872
                foreach ($return as $elem) {
0 ignored issues
show
Bug introduced by
The expression $return of type string is not traversable.
Loading history...
1873
                    $list[$line][$column] = $elem;
1874
                    $column++;
1875
                }
1876
                $answers_of_user = [];
1877
                $line++;
1878
                $column = 0;
1879
            }
1880
            if ('open' == $possible_answers_type[$row['question_id']] || 'comment' == $possible_answers_type[$row['question_id']]) {
1881
                $temp_id = 'open'.$open_question_iterator;
1882
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1883
                $open_question_iterator++;
1884
            } else {
1885
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1886
            }
1887
            $old_user = $row['user'];
1888
        }
1889
1890
        $return = self::export_complete_report_row_xls(
1891
            $survey_data,
1892
            $possible_answers,
1893
            $answers_of_user,
1894
            $old_user,
1895
            true
1896
        );
1897
1898
        // this is to display the last user
1899
        foreach ($return as $elem) {
0 ignored issues
show
Bug introduced by
The expression $return of type string is not traversable.
Loading history...
1900
            $list[$line][$column] = $elem;
1901
            $column++;
1902
        }
1903
1904
        Export::arrayToXls($list, $filename);
1905
1906
        return null;
1907
    }
1908
1909
    /**
1910
     * Add a line to the csv file.
1911
     *
1912
     * @param array Possible answers
1913
     * @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...
1914
     * @param mixed User ID or user details as string - Used as a string in the result string
1915
     * @param bool Whether to display user fields or not
1916
     *
1917
     * @return string One line of the csv file
1918
     */
1919
    public static function export_complete_report_row_xls(
1920
        $survey_data,
1921
        $possible_options,
1922
        $answers_of_user,
1923
        $user,
1924
        $display_extra_user_fields = false
1925
    ) {
1926
        $return = [];
1927
        if (0 == $survey_data['anonymous']) {
1928
            if (0 !== intval($user)) {
1929
                $userInfo = api_get_user_info($user);
1930
                if ($userInfo) {
1931
                    $user_displayed = $userInfo['complete_name_with_username'];
1932
                } else {
1933
                    $user_displayed = '-';
1934
                }
1935
                $return[] = $user_displayed;
1936
            } else {
1937
                $return[] = $user;
1938
            }
1939
        } else {
1940
            $return[] = '-'; // The user column
1941
        }
1942
1943
        if ($display_extra_user_fields) {
1944
            //show user fields data, if any, for this user
1945
            $user_fields_values = UserManager::get_extra_user_data(
1946
                $user,
1947
                false,
1948
                false,
1949
                false,
1950
                true
1951
            );
1952
            foreach ($user_fields_values as $value) {
1953
                $return[] = api_html_entity_decode(strip_tags($value), ENT_QUOTES);
1954
            }
1955
        }
1956
1957
        if (is_array($possible_options)) {
1958
            foreach ($possible_options as $question_id => &$possible_option) {
1959
                if (is_array($possible_option) && count($possible_option) > 0) {
1960
                    foreach ($possible_option as $option_id => &$value) {
1961
                        $my_answers_of_user = isset($answers_of_user[$question_id])
1962
                            ? $answers_of_user[$question_id]
1963
                            : [];
1964
                        $key = array_keys($my_answers_of_user);
1965
                        if (isset($key[0]) && 'open' == substr($key[0], 0, 4)) {
1966
                            $return[] = api_html_entity_decode(
1967
                                strip_tags($answers_of_user[$question_id][$key[0]]['option_id']),
1968
                                ENT_QUOTES
1969
                            );
1970
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1971
                            if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1972
                                $return[] = $answers_of_user[$question_id][$option_id]['value'];
1973
                            } else {
1974
                                $return[] = 'v';
1975
                            }
1976
                        } else {
1977
                            $return[] = '';
1978
                        }
1979
                    }
1980
                }
1981
            }
1982
        }
1983
1984
        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...
1985
    }
1986
1987
    /**
1988
     * This function displays the comparative report which
1989
     * allows you to compare two questions
1990
     * A comparative report creates a table where one question
1991
     * is on the x axis and a second question is on the y axis.
1992
     * In the intersection is the number of people who have
1993
     * answered positive on both options.
1994
     *
1995
     * @return string HTML code
1996
     *
1997
     * @author Patrick Cool <[email protected]>, Ghent University
1998
     *
1999
     * @version February 2007
2000
     */
2001
    public static function display_comparative_report()
2002
    {
2003
        // Allowed question types for comparative report
2004
        $allowed_question_types = [
2005
            'yesno',
2006
            'multiplechoice',
2007
            'multipleresponse',
2008
            'dropdown',
2009
            'percentage',
2010
            'score',
2011
        ];
2012
2013
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
2014
2015
        // Getting all the questions
2016
        $questions = SurveyManager::get_questions($surveyId);
2017
2018
        // Actions bar
2019
        echo '<div class="actions">';
2020
        echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq()
2021
            .'">'
2022
            .Display::return_icon(
2023
                'back.png',
2024
                get_lang('Back to').' '.get_lang('Reporting overview'),
2025
                [],
2026
                ICON_SIZE_MEDIUM
2027
            )
2028
            .'</a>';
2029
        echo '</div>';
2030
2031
        // Displaying an information message that only the questions with predefined answers can be used in a comparative report
2032
        echo Display::return_message(get_lang('Only questions with predefined answers can be used'), 'normal', false);
2033
2034
        $xAxis = isset($_GET['xaxis']) ? Security::remove_XSS($_GET['xaxis']) : '';
2035
        $yAxis = isset($_GET['yaxis']) ? Security::remove_XSS($_GET['yaxis']) : '';
2036
2037
        $url = api_get_self().'?'.api_get_cidreq().'&action='.Security::remove_XSS($_GET['action'])
2038
            .'&survey_id='.$surveyId.'&xaxis='.$xAxis.'&y='.$yAxis;
2039
2040
        $form = new FormValidator('compare', 'get', $url);
2041
        $form->addHidden('action', Security::remove_XSS($_GET['action']));
2042
        $form->addHidden('survey_id', $surveyId);
2043
        $optionsX = ['----'];
2044
        $optionsY = ['----'];
2045
        $defaults = [];
2046
        foreach ($questions as $key => &$question) {
2047
            // Ignored tagged questions
2048
            if ($question) {
2049
                if (false !== strpos($question['question'], '{{')) {
2050
                    $question = null;
2051
                    continue;
2052
                }
2053
            }
2054
            if (is_array($allowed_question_types)) {
2055
                if (in_array($question['type'], $allowed_question_types)) {
2056
                    if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) {
2057
                        $defaults['xaxis'] = $question['question_id'];
2058
                    }
2059
2060
                    if (isset($_GET['yaxis']) && $_GET['yaxis'] == $question['question_id']) {
2061
                        $defaults['yaxis'] = $question['question_id'];
2062
                    }
2063
2064
                    $optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2065
                    $optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2066
                }
2067
            }
2068
        }
2069
2070
        $form->addSelect('xaxis', get_lang('Select the question on the X axis'), $optionsX);
2071
        $form->addSelect('yaxis', get_lang('Select the question on the Y axis'), $optionsY);
2072
2073
        $form->addButtonSearch(get_lang('Compare questions'));
2074
        $form->setDefaults($defaults);
2075
        $form->display();
2076
2077
        // Getting all the information of the x axis
2078
        if (is_numeric($xAxis)) {
2079
            $question_x = SurveyManager::get_question($xAxis);
2080
        }
2081
2082
        // Getting all the information of the y axis
2083
        if (is_numeric($yAxis)) {
2084
            $question_y = SurveyManager::get_question($yAxis);
2085
        }
2086
2087
        if (is_numeric($xAxis) && is_numeric($yAxis)) {
2088
            // Getting the answers of the two questions
2089
            $answers_x = self::get_answers_of_question_by_user($surveyId, $xAxis);
2090
            $answers_y = self::get_answers_of_question_by_user($surveyId, $yAxis);
2091
2092
            // Displaying the table
2093
            $tableHtml = '<table border="1" class="data_table">';
2094
            $xOptions = [];
2095
            // The header
2096
            $tableHtml .= '<tr>';
2097
            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...
2098
                if (0 == $ii) {
2099
                    $tableHtml .= '<th>&nbsp;</th>';
2100
                } else {
2101
                    if ('score' == $question_x['type']) {
2102
                        for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2103
                            $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'<br />'.$x.'</th>';
2104
                        }
2105
                        $x = '';
2106
                    } else {
2107
                        $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'</th>';
2108
                    }
2109
                    $optionText = strip_tags($question_x['answers'][$ii - 1]);
2110
                    $optionText = html_entity_decode($optionText);
2111
                    array_push($xOptions, trim($optionText));
2112
                }
2113
            }
2114
            $tableHtml .= '</tr>';
2115
            $chartData = [];
2116
            // The main part
2117
            for ($ij = 0; $ij < count($question_y['answers']); $ij++) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_y does not seem to be defined for all execution paths leading up to this point.
Loading history...
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...
2118
                $currentYQuestion = strip_tags($question_y['answers'][$ij]);
2119
                $currentYQuestion = html_entity_decode($currentYQuestion);
2120
                // The Y axis is a scoring question type so we have more rows than the options (actually options * maximum score)
2121
                if ('score' == $question_y['type']) {
2122
                    for ($y = 1; $y <= $question_y['maximum_score']; $y++) {
2123
                        $tableHtml .= '<tr>';
2124
                        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...
2125
                            if ('score' == $question_x['type']) {
2126
                                for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2127
                                    if (0 == $ii) {
2128
                                        $tableHtml .= '<th>'.$question_y['answers'][($ij)].' '.$y.'</th>';
2129
                                        break;
2130
                                    } else {
2131
                                        $tableHtml .= '<td align="center">';
2132
                                        $votes = self::comparative_check(
2133
                                            $answers_x,
2134
                                            $answers_y,
2135
                                            $question_x['answersid'][($ii - 1)],
2136
                                            $question_y['answersid'][($ij)],
2137
                                            $x,
2138
                                            $y
2139
                                        );
2140
                                        $tableHtml .= $votes;
2141
                                        array_push(
2142
                                            $chartData,
2143
                                            [
2144
                                                'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2145
                                                'option' => $x,
2146
                                                'votes' => $votes,
2147
                                            ]
2148
                                        );
2149
                                        $tableHtml .= '</td>';
2150
                                    }
2151
                                }
2152
                            } else {
2153
                                if (0 == $ii) {
2154
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].' '.$y.'</th>';
2155
                                } else {
2156
                                    $tableHtml .= '<td align="center">';
2157
                                    $votes = self::comparative_check(
2158
                                        $answers_x,
2159
                                        $answers_y,
2160
                                        $question_x['answersid'][($ii - 1)],
2161
                                        $question_y['answersid'][($ij)],
2162
                                        0,
2163
                                        $y
2164
                                    );
2165
                                    $tableHtml .= $votes;
2166
                                    array_push(
2167
                                        $chartData,
2168
                                        [
2169
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2170
                                            'option' => $y,
2171
                                            'votes' => $votes,
2172
                                        ]
2173
                                    );
2174
                                    $tableHtml .= '</td>';
2175
                                }
2176
                            }
2177
                        }
2178
                        $tableHtml .= '</tr>';
2179
                    }
2180
                } else {
2181
                    // The Y axis is NOT a score question type so the number of rows = the number of options
2182
                    $tableHtml .= '<tr>';
2183
                    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...
2184
                        if ('score' == $question_x['type']) {
2185
                            for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2186
                                if (0 == $ii) {
2187
                                    $tableHtml .= '<th>'.$question_y['answers'][$ij].'</th>';
2188
                                    break;
2189
                                } else {
2190
                                    $tableHtml .= '<td align="center">';
2191
                                    $votes = self::comparative_check(
2192
                                        $answers_x,
2193
                                        $answers_y,
2194
                                        $question_x['answersid'][($ii - 1)],
2195
                                        $question_y['answersid'][($ij)],
2196
                                        $x,
2197
                                        0
2198
                                    );
2199
                                    $tableHtml .= $votes;
2200
                                    array_push(
2201
                                        $chartData,
2202
                                        [
2203
                                            'serie' => [$currentYQuestion, $xOptions[$ii - 1]],
2204
                                            'option' => $x,
2205
                                            'votes' => $votes,
2206
                                        ]
2207
                                    );
2208
                                    $tableHtml .= '</td>';
2209
                                }
2210
                            }
2211
                        } else {
2212
                            if (0 == $ii) {
2213
                                $tableHtml .= '<th>'.$question_y['answers'][($ij)].'</th>';
2214
                            } else {
2215
                                $tableHtml .= '<td align="center">';
2216
                                $votes = self::comparative_check(
2217
                                    $answers_x,
2218
                                    $answers_y,
2219
                                    $question_x['answersid'][($ii - 1)],
2220
                                    $question_y['answersid'][($ij)]
2221
                                );
2222
                                $tableHtml .= $votes;
2223
                                array_push(
2224
                                    $chartData,
2225
                                    [
2226
                                        'serie' => $xOptions[$ii - 1],
2227
                                        'option' => $currentYQuestion,
2228
                                        'votes' => $votes,
2229
                                    ]
2230
                                );
2231
                                $tableHtml .= '</td>';
2232
                            }
2233
                        }
2234
                    }
2235
                    $tableHtml .= '</tr>';
2236
                }
2237
            }
2238
            $tableHtml .= '</table>';
2239
            echo '<div id="chartContainer" class="col-md-12">';
2240
            echo self::drawChart($chartData, true);
2241
            echo '</div>';
2242
            echo $tableHtml;
2243
        }
2244
    }
2245
2246
    /**
2247
     * Get all the answers of a question grouped by user.
2248
     *
2249
     * @param int $survey_id   Survey ID
2250
     * @param int $question_id Question ID
2251
     *
2252
     * @return array Array containing all answers of all users, grouped by user
2253
     *
2254
     * @author Patrick Cool <[email protected]>, Ghent University
2255
     *
2256
     * @version February 2007 - Updated March 2008
2257
     */
2258
    public static function get_answers_of_question_by_user($survey_id, $question_id)
2259
    {
2260
        $course_id = api_get_course_int_id();
2261
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
2262
2263
        $sql = "SELECT * FROM $table_survey_answer
2264
                WHERE
2265
                  c_id = $course_id AND
2266
                  survey_id='".intval($survey_id)."' AND
2267
                  question_id='".intval($question_id)."'
2268
                ORDER BY USER ASC";
2269
        $result = Database::query($sql);
2270
        $return = [];
2271
        while ($row = Database::fetch_array($result)) {
2272
            if (0 == $row['value']) {
2273
                $return[$row['user']][] = $row['option_id'];
2274
            } else {
2275
                $return[$row['user']][] = $row['option_id'].'*'.$row['value'];
2276
            }
2277
        }
2278
2279
        return $return;
2280
    }
2281
2282
    /**
2283
     * Count the number of users who answer positively on both options.
2284
     *
2285
     * @param array All answers of the x axis
2286
     * @param array All answers of the y axis
2287
     * @param int x axis value (= the option_id of the first question)
2288
     * @param int y axis value (= the option_id of the second question)
2289
     *
2290
     * @return int Number of users who have answered positively to both options
2291
     *
2292
     * @author Patrick Cool <[email protected]>, Ghent University
2293
     *
2294
     * @version February 2007
2295
     */
2296
    public static function comparative_check(
2297
        $answers_x,
2298
        $answers_y,
2299
        $option_x,
2300
        $option_y,
2301
        $value_x = 0,
2302
        $value_y = 0
2303
    ) {
2304
        if (0 == $value_x) {
2305
            $check_x = $option_x;
2306
        } else {
2307
            $check_x = $option_x.'*'.$value_x;
2308
        }
2309
        if (0 == $value_y) {
2310
            $check_y = $option_y;
2311
        } else {
2312
            $check_y = $option_y.'*'.$value_y;
2313
        }
2314
2315
        $counter = 0;
2316
        if (is_array($answers_x)) {
2317
            foreach ($answers_x as $user => &$answers) {
2318
                // Check if the user has given $option_x as answer
2319
                if (in_array($check_x, $answers)) {
2320
                    // Check if the user has given $option_y as an answer
2321
                    if (!is_null($answers_y[$user]) &&
2322
                        in_array($check_y, $answers_y[$user])
2323
                    ) {
2324
                        $counter++;
2325
                    }
2326
                }
2327
            }
2328
        }
2329
2330
        return $counter;
2331
    }
2332
2333
    public static function saveInviteMail(CSurvey $survey, $content, $subject, $remind)
2334
    {
2335
        // Database table definition
2336
        if ($remind) {
2337
            $survey->setReminderMail($content);
2338
        } else {
2339
            $survey->setInviteMail($content);
2340
        }
2341
2342
        $survey->setMailSubject($subject);
2343
        $em = Database::getManager();
2344
        $em->persist($survey);
2345
        $em->flush();
2346
    }
2347
2348
    /**
2349
     * This function saves all the invitations of course users
2350
     * and additional users in the database
2351
     * and sends the invitations by email.
2352
     *
2353
     * @param $users_array Users $array array can be both a list of course uids AND a list of additional emailaddresses
2354
     * @param $invitation_title Title $string of the invitation, used as the title of the mail
2355
     * @param $invitation_text Text $string of the invitation, used as the text of the mail.
2356
     *                         The text has to contain a **link** string or this will automatically be added to the end
2357
     * @param int  $reminder
2358
     * @param bool $sendmail
2359
     * @param int  $remindUnAnswered
2360
     * @param bool $isAdditionalEmail
2361
     * @param bool $hideLink
2362
     *
2363
     * @author Patrick Cool <[email protected]>, Ghent University
2364
     * @author Julio Montoya - Adding auto-generated link support
2365
     *
2366
     * @version January 2007
2367
     */
2368
    public static function saveInvitations(
2369
        $users_array,
2370
        $invitation_title,
2371
        $invitation_text,
2372
        $reminder = 0,
2373
        $sendmail = false,
2374
        $remindUnAnswered = 0,
2375
        $isAdditionalEmail = false,
2376
        $hideLink = false
2377
    ) {
2378
        if (!is_array($users_array)) {
2379
            return 0;
2380
        }
2381
2382
        // Getting the survey information
2383
        $survey_data = SurveyManager::get_survey($_GET['survey_id']);
2384
        $survey_invitations = self::get_invitations($survey_data['survey_code']);
2385
        $already_invited = self::get_invited_users($survey_data['code']);
2386
2387
        // Remind unanswered is a special version of remind all reminder
2388
        $exclude_users = [];
2389
        if (1 == $remindUnAnswered) {
2390
            // Remind only unanswered users
2391
            $reminder = 1;
2392
            $exclude_users = SurveyManager::get_people_who_filled_survey($_GET['survey_id']);
2393
        }
2394
2395
        $counter = 0; // Nr of invitations "sent" (if sendmail option)
2396
        $course_id = api_get_course_int_id();
2397
        $session_id = api_get_session_id();
2398
2399
        if (false == $isAdditionalEmail) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
2400
            $result = CourseManager::separateUsersGroups($users_array);
2401
            $groupList = $result['groups'];
2402
            $users_array = $result['users'];
2403
2404
            foreach ($groupList as $groupId) {
2405
                $userGroupList = GroupManager::getStudents($groupId, true);
2406
                $userGroupIdList = array_column($userGroupList, 'user_id');
2407
                $users_array = array_merge($users_array, $userGroupIdList);
2408
2409
                $params = [
2410
                    'c_id' => $course_id,
2411
                    'session_id' => $session_id,
2412
                    'group_id' => $groupId,
2413
                    'survey_code' => $survey_data['code'],
2414
                ];
2415
2416
                $invitationExists = self::invitationExists(
2417
                    $course_id,
2418
                    $session_id,
2419
                    $groupId,
2420
                    $survey_data['code']
2421
                );
2422
                if (empty($invitationExists)) {
2423
                    self::save_invitation($params);
2424
                }
2425
            }
2426
        }
2427
2428
        $users_array = array_unique($users_array);
2429
        foreach ($users_array as $key => $value) {
2430
            if (!isset($value) || '' == $value) {
2431
                continue;
2432
            }
2433
2434
            // Skip user if reminding only unanswered people
2435
            if (in_array($value, $exclude_users)) {
2436
                continue;
2437
            }
2438
2439
            // Get the unique invitation code if we already have it
2440
            if (1 == $reminder && array_key_exists($value, $survey_invitations)) {
2441
                $invitation_code = $survey_invitations[$value]['invitation_code'];
2442
            } else {
2443
                $invitation_code = md5($value.microtime());
2444
            }
2445
            $new_user = false; // User not already invited
2446
            // Store the invitation if user_id not in $already_invited['course_users'] OR email is not in $already_invited['additional_users']
2447
            $addit_users_array = isset($already_invited['additional_users']) && !empty($already_invited['additional_users'])
2448
                    ? explode(';', $already_invited['additional_users'])
2449
                    : [];
2450
            $my_alredy_invited = null == $already_invited['course_users'] ? [] : $already_invited['course_users'];
2451
            if ((is_numeric($value) && !in_array($value, $my_alredy_invited)) ||
2452
                (!is_numeric($value) && !in_array($value, $addit_users_array))
2453
            ) {
2454
                $new_user = true;
2455
                if (!array_key_exists($value, $survey_invitations)) {
2456
                    $params = [
2457
                        'c_id' => $course_id,
2458
                        'session_id' => $session_id,
2459
                        'user' => $value,
2460
                        'survey_code' => $survey_data['code'],
2461
                        'invitation_code' => $invitation_code,
2462
                        'invitation_date' => api_get_utc_datetime(),
2463
                    ];
2464
                    self::save_invitation($params);
2465
                }
2466
            }
2467
2468
            // Send the email if checkboxed
2469
            if (($new_user || 1 == $reminder) && $sendmail) {
2470
                // Make a change for absolute url
2471
                if (isset($invitation_text)) {
2472
                    $invitation_text = api_html_entity_decode($invitation_text, ENT_QUOTES);
2473
                    $invitation_text = str_replace('src="../../', 'src="'.api_get_path(WEB_PATH), $invitation_text);
2474
                    $invitation_text = trim(stripslashes($invitation_text));
2475
                }
2476
                self::send_invitation_mail(
2477
                    $value,
2478
                    $invitation_code,
2479
                    $invitation_title,
2480
                    $invitation_text,
2481
                    $hideLink
2482
                );
2483
                $counter++;
2484
            }
2485
        }
2486
2487
        return $counter; // Number of invitations sent
2488
    }
2489
2490
    /**
2491
     * @param $params
2492
     *
2493
     * @return bool|int
2494
     */
2495
    public static function save_invitation($params)
2496
    {
2497
        // Database table to store the invitations data
2498
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
2499
        if (!empty($params['c_id']) &&
2500
            (!empty($params['user']) || !empty($params['group_id'])) &&
2501
            !empty($params['survey_code'])
2502
        ) {
2503
            if (!isset($params['survey_invitation_id'])) {
2504
                $params['survey_invitation_id'] = 0;
2505
            }
2506
            if (!isset($params['answered'])) {
2507
                $params['answered'] = 0;
2508
            }
2509
            if (!isset($params['group_id'])) {
2510
                $params['group_id'] = 0;
2511
            }
2512
            $insertId = Database::insert($table, $params);
2513
            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...
2514
                $sql = "UPDATE $table
2515
                        SET survey_invitation_id = $insertId
2516
                        WHERE iid = $insertId";
2517
                Database::query($sql);
2518
            }
2519
2520
            return $insertId;
2521
        }
2522
2523
        return false;
2524
    }
2525
2526
    /**
2527
     * @param int    $courseId
2528
     * @param int    $sessionId
2529
     * @param int    $groupId
2530
     * @param string $surveyCode
2531
     *
2532
     * @return int
2533
     */
2534
    public static function invitationExists($courseId, $sessionId, $groupId, $surveyCode)
2535
    {
2536
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
2537
        $courseId = (int) $courseId;
2538
        $sessionId = (int) $sessionId;
2539
        $groupId = (int) $groupId;
2540
        $surveyCode = Database::escape_string($surveyCode);
2541
2542
        $sql = "SELECT survey_invitation_id FROM $table
2543
                WHERE
2544
                    c_id = $courseId AND
2545
                    session_id = $sessionId AND
2546
                    group_id = $groupId AND
2547
                    survey_code = '$surveyCode'
2548
                ";
2549
        $result = Database::query($sql);
2550
2551
        return Database::num_rows($result);
2552
    }
2553
2554
    /**
2555
     * Send the invitation by mail.
2556
     *
2557
     * @param int invitedUser - the userId (course user) or emailaddress of additional user
2558
     * $param string $invitation_code - the unique invitation code for the URL
2559
     */
2560
    public static function send_invitation_mail(
2561
        $invitedUser,
2562
        $invitation_code,
2563
        $invitation_title,
2564
        $invitation_text,
2565
        $hideLink = false
2566
    ) {
2567
        $_user = api_get_user_info();
2568
        $_course = api_get_course_info();
2569
        $sessionId = api_get_session_id();
2570
2571
        // Replacing the **link** part with a valid link for the user
2572
        $link = self::generateFillSurveyLink($invitation_code, $_course, $sessionId);
2573
        if ($hideLink) {
2574
            $full_invitation_text = str_replace('**link**', '', $invitation_text);
2575
        } else {
2576
            $text_link = '<a href="'.$link.'">'.get_lang('Click here to answer the survey')."</a><br />\r\n<br />\r\n"
2577
                .get_lang('or copy paste the following url :')." <br /> \r\n <br /> \r\n ".$link;
2578
2579
            $replace_count = 0;
2580
            $full_invitation_text = api_str_ireplace('**link**', $text_link, $invitation_text, $replace_count);
2581
            if ($replace_count < 1) {
2582
                $full_invitation_text = $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
2583
            }
2584
        }
2585
2586
        // Sending the mail
2587
        $sender_name = api_get_person_name($_user['firstName'], $_user['lastName'], null, PERSON_NAME_EMAIL_ADDRESS);
2588
        $sender_email = $_user['mail'];
2589
        $sender_user_id = api_get_user_id();
2590
2591
        $replyto = [];
2592
        if ('noreply' == api_get_setting('survey_email_sender_noreply')) {
2593
            $noreply = api_get_setting('noreply_email_address');
2594
            if (!empty($noreply)) {
2595
                $replyto['Reply-to'] = $noreply;
2596
                $sender_name = $noreply;
2597
                $sender_email = $noreply;
2598
                $sender_user_id = null;
2599
            }
2600
        }
2601
2602
        // Optionally: finding the e-mail of the course user
2603
        if (is_numeric($invitedUser)) {
2604
            MessageManager::send_message(
2605
                $invitedUser,
2606
                $invitation_title,
2607
                $full_invitation_text,
2608
                [],
2609
                [],
2610
                null,
2611
                null,
2612
                null,
2613
                null,
2614
                $sender_user_id,
2615
                true
2616
            );
2617
        } else {
2618
            @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

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

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

3832
        if (/** @scrutinizer ignore-deprecated */ api_browser_support('svg')) {
Loading history...
3833
            $htmlChart .= api_get_js('d3/d3.v3.5.4.min.js');
3834
            $htmlChart .= api_get_js('dimple.v2.1.2.min.js').'
3835
            <script>
3836
            var svg = dimple.newSvg("#'.$chartContainerId.'", "100%", 400);
3837
            var data = [';
3838
            $serie = [];
3839
            $order = [];
3840
            foreach ($chartData as $chartDataElement) {
3841
                $htmlChart .= '{"';
3842
                if (!$hasSerie) {
3843
                    $htmlChart .= get_lang("Option").'":"'.$chartDataElement['option'].'", "';
3844
                    array_push($order, $chartDataElement['option']);
3845
                } else {
3846
                    if (!is_array($chartDataElement['serie'])) {
3847
                        $htmlChart .= get_lang("Option").'":"'.$chartDataElement['serie'].'", "'.
3848
                            get_lang("Score").'":"'.$chartDataElement['option'].'", "';
3849
                        array_push($serie, $chartDataElement['serie']);
3850
                    } else {
3851
                        $htmlChart .= get_lang("Serie").'":"'.$chartDataElement['serie'][0].'", "'.
3852
                            get_lang("Option").'":"'.$chartDataElement['serie'][1].'", "'.
3853
                            get_lang("Score").'":"'.$chartDataElement['option'].'", "';
3854
                    }
3855
                }
3856
                $htmlChart .= get_lang("Votes").'":"'.$chartDataElement['votes'].
3857
                    '"},';
3858
            }
3859
            rtrim($htmlChart, ",");
3860
            $htmlChart .= '];
3861
                var myChart = new dimple.chart(svg, data);
3862
                myChart.addMeasureAxis("y", "'.get_lang("Votes").'");';
3863
            if (!$hasSerie) {
3864
                $htmlChart .= 'var xAxisCategory = myChart.addCategoryAxis("x", "'.get_lang("Option").'");
3865
                    xAxisCategory.addOrderRule('.json_encode($order).');
3866
                    myChart.addSeries("'.get_lang("Option").'", dimple.plot.bar);';
3867
            } else {
3868
                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 3840. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
3869
                    $serie = array_values(array_unique($serie));
3870
                    $htmlChart .= 'var xAxisCategory = myChart.addCategoryAxis("x", ["'.get_lang("Option").'","'
3871
                        .get_lang("Score").'"]);
3872
                        xAxisCategory.addOrderRule('.json_encode($serie).');
3873
                        xAxisCategory.addGroupOrderRule("'.get_lang("Score").'");
3874
                        myChart.addSeries("'.get_lang("Option").'", dimple.plot.bar);';
3875
                } else {
3876
                    $htmlChart .= 'myChart.addCategoryAxis("x", ["'.get_lang("Option").'","'.get_lang("Score").'"]);
3877
                        myChart.addSeries("'.get_lang("Serie").'", dimple.plot.bar);';
3878
                }
3879
            }
3880
            $htmlChart .= 'myChart.draw();
3881
                </script>';
3882
        }
3883
3884
        return $htmlChart;
3885
    }
3886
3887
    /**
3888
     * Set a flag to the current survey as answered by the current user.
3889
     *
3890
     * @param string $surveyCode The survey code
3891
     * @param int    $courseId   The course ID
3892
     */
3893
    public static function flagSurveyAsAnswered($surveyCode, $courseId)
3894
    {
3895
        $currentUserId = api_get_user_id();
3896
        $flag = sprintf('%s-%s-%d', $courseId, $surveyCode, $currentUserId);
3897
3898
        if (!isset($_SESSION['filled_surveys'])) {
3899
            $_SESSION['filled_surveys'] = [];
3900
        }
3901
3902
        $_SESSION['filled_surveys'][] = $flag;
3903
    }
3904
3905
    /**
3906
     * Check whether a survey was answered by the current user.
3907
     *
3908
     * @param string $surveyCode The survey code
3909
     * @param int    $courseId   The course ID
3910
     *
3911
     * @return bool
3912
     */
3913
    public static function isSurveyAnsweredFlagged($surveyCode, $courseId)
3914
    {
3915
        $currentUserId = api_get_user_id();
3916
        $flagToCheck = sprintf('%s-%s-%d', $courseId, $surveyCode, $currentUserId);
3917
3918
        if (!isset($_SESSION['filled_surveys'])) {
3919
            return false;
3920
        }
3921
3922
        if (!is_array($_SESSION['filled_surveys'])) {
3923
            return false;
3924
        }
3925
3926
        foreach ($_SESSION['filled_surveys'] as $flag) {
3927
            if ($flagToCheck != $flag) {
3928
                continue;
3929
            }
3930
3931
            return true;
3932
        }
3933
3934
        return false;
3935
    }
3936
3937
    /**
3938
     * Check if the current survey has answers.
3939
     *
3940
     * @param int $surveyId
3941
     *
3942
     * @return bool return true if the survey has answers, false otherwise
3943
     */
3944
    public static function checkIfSurveyHasAnswers($surveyId)
3945
    {
3946
        $tableSurveyAnswer = Database::get_course_table(TABLE_SURVEY_ANSWER);
3947
        $courseId = api_get_course_int_id();
3948
        $surveyId = (int) $surveyId;
3949
3950
        if (empty($courseId) || empty($surveyId)) {
3951
            return false;
3952
        }
3953
3954
        $sql = "SELECT * FROM $tableSurveyAnswer
3955
                WHERE
3956
                    c_id = $courseId AND
3957
                    survey_id = '".$surveyId."'
3958
                ORDER BY answer_id, user ASC";
3959
        $result = Database::query($sql);
3960
        $response = Database::affected_rows($result);
3961
3962
        return $response > 0;
3963
    }
3964
3965
    /**
3966
     * Get the pending surveys for a user.
3967
     *
3968
     * @param int $userId
3969
     *
3970
     * @return array
3971
     */
3972
    public static function getUserPendingInvitations($userId)
3973
    {
3974
        $now = api_get_utc_datetime(null, false, true);
3975
3976
        $dql = "
3977
            SELECT s, si FROM ChamiloCourseBundle:CSurvey s
3978
            INNER JOIN ChamiloCourseBundle:CSurveyInvitation si
3979
                WITH (s.code = si.surveyCode AND s.cId = si.cId AND s.sessionId = si.sessionId )
3980
            WHERE
3981
                si.user = :user_id AND
3982
                s.availFrom <= :now AND
3983
                s.availTill >= :now AND
3984
                si.answered = 0
3985
            ORDER BY s.availTill ASC
3986
        ";
3987
3988
        $pendingSurveys = Database::getManager()
3989
            ->createQuery($dql)
3990
            ->setParameters(['user_id' => $userId, 'now' => $now->format('Y-m-d')])
3991
            ->getResult();
3992
3993
        return $pendingSurveys;
3994
    }
3995
3996
    /**
3997
     * @param string $surveyCode
3998
     * @param int    $courseId
3999
     * @param int    $sessionId
4000
     *
4001
     * @return array
4002
     */
4003
    public static function getSentInvitations($surveyCode, $courseId, $sessionId = 0)
4004
    {
4005
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
4006
        $tblSurveyInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
4007
4008
        $sessionCondition = api_get_session_condition($sessionId);
4009
        $surveyCode = Database::escape_string($surveyCode);
4010
        $courseId = (int) $courseId;
4011
4012
        $sql = "SELECT survey_invitation.*, user.firstname, user.lastname, user.email
4013
                FROM $tblSurveyInvitation survey_invitation
4014
                LEFT JOIN $tblUser user
4015
                ON (survey_invitation.user = user.id AND survey_invitation.c_id = $courseId)
4016
                WHERE
4017
                    survey_invitation.survey_code = '$surveyCode'
4018
                    AND survey_invitation.c_id = $courseId
4019
                    $sessionCondition";
4020
4021
        $query = Database::query($sql);
4022
4023
        return Database::store_result($query);
4024
    }
4025
4026
    /**
4027
     * @param string $code       invitation code
4028
     * @param array  $courseInfo
4029
     * @param int    $sessionId
4030
     * @param string $surveyCode
4031
     *
4032
     * @return string
4033
     */
4034
    public static function generateFillSurveyLink($code, $courseInfo, $sessionId, $surveyCode = '')
4035
    {
4036
        $code = Security::remove_XSS($code);
4037
        $sessionId = (int) $sessionId;
4038
4039
        if (empty($courseInfo)) {
4040
            return '';
4041
        }
4042
4043
        $params = [
4044
            'invitationcode' => $code,
4045
            'cid' => $courseInfo['code'],
4046
            'course' => $courseInfo['code'],
4047
            'sid' => $sessionId,
4048
        ];
4049
4050
        if (!empty($surveyCode)) {
4051
            $params['scode'] = Security::remove_XSS($surveyCode);
4052
        }
4053
        if (!empty($courseInfo['language'])) {
4054
            $params['language'] = $courseInfo['language'];
4055
        }
4056
4057
        return api_get_path(WEB_CODE_PATH).'survey/fillsurvey.php?'.http_build_query($params);
4058
    }
4059
}
4060