Passed
Push — master ( 3ad0be...6ad90b )
by Julito
07:30
created

SurveyUtil::saveInviteMail()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 4
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Framework\Container;
6
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
8
use Chamilo\CourseBundle\Entity\CGroup;
9
use Chamilo\CourseBundle\Entity\CSurvey;
10
use Chamilo\CourseBundle\Entity\CSurveyAnswer;
11
use Chamilo\CourseBundle\Entity\CSurveyInvitation;
12
use Chamilo\CourseBundle\Entity\CSurveyQuestion;
13
use Chamilo\CourseBundle\Entity\CSurveyQuestionOption;
14
use ChamiloSession as Session;
15
16
/**
17
 * This class offers a series of general utility functions for survey querying and display.
18
 */
19
class SurveyUtil
20
{
21
    /**
22
     * Checks whether the given survey has a pagebreak question as the first
23
     * or the last question.
24
     * If so, break the current process, displaying an error message.
25
     *
26
     * @param int  $survey_id Survey ID (database ID)
27
     * @param bool $continue  Optional. Whether to continue the current
28
     *                        process or exit when breaking condition found. Defaults to true (do not break).
29
     */
30
    public static function check_first_last_question($survey_id, $continue = true)
31
    {
32
        // Table definitions
33
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
34
        $course_id = api_get_course_int_id();
35
        $survey_id = (int) $survey_id;
36
37
        // Getting the information of the question
38
        $sql = "SELECT * FROM $tbl_survey_question
39
                WHERE survey_id='".$survey_id."'
40
                ORDER BY sort ASC";
41
        $result = Database::query($sql);
42
        $total = Database::num_rows($result);
43
        $counter = 1;
44
        $error = false;
45
        while ($row = Database::fetch_array($result, 'ASSOC')) {
46
            if (1 == $counter && 'pagebreak' === $row['type']) {
47
                echo Display::return_message(get_lang('The page break cannot be the first'), 'error', false);
48
                $error = true;
49
            }
50
            if ($counter == $total && 'pagebreak' === $row['type']) {
51
                echo Display::return_message(get_lang('The page break cannot be the last one'), 'error', false);
52
                $error = true;
53
            }
54
            $counter++;
55
        }
56
57
        if (!$continue && $error) {
58
            Display::display_footer();
59
            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...
60
        }
61
    }
62
63
    /**
64
     * This function removes an (or multiple) answer(s) of a user on a question of a survey.
65
     *
66
     * @param mixed   The user id or email of the person who fills the survey
67
     * @param int The survey id
68
     * @param int The question id
69
     * @param int The option id
70
     *
71
     * @author Patrick Cool <[email protected]>, Ghent University
72
     *
73
     * @version January 2007
74
     */
75
    public static function remove_answer($user, $survey_id, $question_id)
76
    {
77
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
78
        $sql = "DELETE FROM $table
79
				WHERE
80
                    user = '".Database::escape_string($user)."' AND
81
                    survey_id = '".intval($survey_id)."' AND
82
                    question_id = '".intval($question_id)."'";
83
        Database::query($sql);
84
    }
85
86
    public static function saveAnswer(
87
        $user,
88
        CSurvey $survey,
89
        CSurveyQuestion $question,
90
        $optionId,
91
        $optionValue,
92
        $otherOption = ''
93
    ) {
94
        // Make the survey anonymous
95
        if (1 == $survey->getAnonymous()) {
96
            $surveyUser = Session::read('surveyuser');
97
            if (empty($surveyUser)) {
98
                $user = md5($user.time());
99
                Session::write('surveyuser', $user);
100
            } else {
101
                $user = Session::read('surveyuser');
102
            }
103
        }
104
105
        if (!empty($otherOption)) {
106
            $optionId = $optionId.'@:@'.$otherOption;
107
        }
108
109
        $answer = new CSurveyAnswer();
110
        $answer
111
            ->setUser($user)
112
            ->setSurvey($survey)
113
            ->setQuestion($question)
114
            ->setOptionId($optionId)
115
            ->setValue((int) $optionValue)
116
        ;
117
118
        $em = Database::getManager();
119
        $em->persist($answer);
120
        $em->flush();
121
122
        $insertId = $answer->getIid();
123
        if ($insertId) {
124
            return true;
125
        }
126
127
        return false;
128
    }
129
130
    /**
131
     * This function checks the parameters that are used in this page.
132
     *
133
     * @return string $people_filled The header, an error and the footer if any parameter fails, else it returns true
134
     *
135
     * @author Patrick Cool <[email protected]>, Ghent University
136
     *
137
     * @version February 2007
138
     */
139
    public static function check_parameters($people_filled)
140
    {
141
        $error = false;
142
143
        // Getting the survey data
144
        $survey_data = SurveyManager::get_survey($_GET['survey_id']);
145
146
        // $_GET['survey_id'] has to be numeric
147
        if (!is_numeric($_GET['survey_id'])) {
148
            $error = get_lang('Unknown survey id');
149
        }
150
151
        // $_GET['action']
152
        $allowed_actions = [
153
            'overview',
154
            'questionreport',
155
            'userreport',
156
            'comparativereport',
157
            'completereport',
158
            'deleteuserreport',
159
        ];
160
        if (isset($_GET['action']) && !in_array($_GET['action'], $allowed_actions)) {
161
            $error = get_lang('Action not allowed');
162
        }
163
164
        // User report
165
        if (isset($_GET['action']) && 'userreport' == $_GET['action']) {
166
            if (0 == $survey_data['anonymous']) {
167
                foreach ($people_filled as $key => &$value) {
168
                    $people_filled_userids[] = $value['invited_user'];
169
                }
170
            } else {
171
                $people_filled_userids = $people_filled;
172
            }
173
174
            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...
175
                $error = get_lang('Unknow user');
176
            }
177
        }
178
179
        // Question report
180
        if (isset($_GET['action']) && 'questionreport' == $_GET['action']) {
181
            if (isset($_GET['question']) && !is_numeric($_GET['question'])) {
182
                $error = get_lang('Unknown question');
183
            }
184
        }
185
186
        if ($error) {
187
            $tool_name = get_lang('Reporting');
188
            Display::addFlash(
189
                Display::return_message(
190
                    get_lang('Error').': '.$error,
191
                    'error',
192
                    false
193
                )
194
            );
195
            Display::display_header($tool_name);
196
            Display::display_footer();
197
            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...
198
        }
199
200
        return true;
201
    }
202
203
    public static function handleReportingActions(CSurvey $survey, array $people_filled = [])
204
    {
205
        $action = $_GET['action'] ?? '';
206
207
        switch ($action) {
208
            case 'questionreport':
209
                self::display_question_report($survey);
210
                break;
211
            case 'userreport':
212
                self::displayUserReport($survey, $people_filled);
213
                break;
214
            case 'comparativereport':
215
                self::display_comparative_report();
216
                break;
217
            case 'completereport':
218
                echo self::displayCompleteReport($survey);
219
                break;
220
            case 'deleteuserreport':
221
                self::delete_user_report($survey, $_GET['user']);
222
                break;
223
        }
224
    }
225
226
    /**
227
     * This function deletes the report of an user who wants to retake the survey.
228
     *
229
     * @param int $survey_id
230
     * @param int $user_id
231
     *
232
     * @author Christian Fasanando Flores <[email protected]>
233
     *
234
     * @version November 2008
235
     */
236
    public static function delete_user_report($survey_id, $user_id)
237
    {
238
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
239
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
240
        $table_survey = Database::get_course_table(TABLE_SURVEY);
241
242
        $course_id = api_get_course_int_id();
243
        $survey_id = (int) $survey_id;
244
        $user_id = Database::escape_string($user_id);
245
246
        if (!empty($survey_id) && !empty($user_id)) {
247
            // delete data from survey_answer by user_id and survey_id
248
            $sql = "DELETE FROM $table_survey_answer
249
			        WHERE c_id = $course_id AND survey_id = '".$survey_id."' AND user = '".$user_id."'";
250
            Database::query($sql);
251
            // update field answered from survey_invitation by user_id and survey_id
252
            $sql = "UPDATE $table_survey_invitation SET answered = '0'
253
			        WHERE
254
			            c_id = $course_id AND
255
			            survey_id = (
256
                            SELECT iid FROM $table_survey
257
                            WHERE
258
                                iid = '".$survey_id."'
259
                        ) AND
260
			            user = '".$user_id."'";
261
            $result = Database::query($sql);
262
        }
263
264
        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...
265
            $message = get_lang('The user\'s answers to the survey have been succesfully removed.').'<br />
266
					<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
267
                .$survey_id.'">'.
268
                get_lang('Go back').'</a>';
269
            echo Display::return_message($message, 'confirmation', false);
270
        }
271
    }
272
273
    /**
274
     * @return string
275
     */
276
    public static function displayUserReportForm(CSurvey $survey, array $people_filled = [])
277
    {
278
        $surveyId = $survey->getIid();
279
        // Step 1: selection of the user
280
        echo "<script>
281
        function jumpMenu(targ,selObj,restore) {
282
            eval(targ+\".location='\"+selObj.options[selObj.selectedIndex].value+\"'\");
283
            if (restore) selObj.selectedIndex=0;
284
        }
285
		</script>";
286
        echo get_lang('Select user who filled the survey').'<br />';
287
        echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
288
        echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
289
            .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
290
            .get_lang('User').'</option>';
291
292
        foreach ($people_filled as $key => &$person) {
293
            if (0 == $survey->getAnonymous()) {
294
                $name = $person['user_info']['complete_name_with_username'];
295
                $id = $person['user_id'];
296
                if ('' == $id) {
297
                    $id = $person['invited_user'];
298
                    $name = $person['invited_user'];
299
                }
300
            } else {
301
                $name = get_lang('Anonymous').' '.($key + 1);
302
                $id = $person;
303
            }
304
            echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
305
                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&user='
306
                .Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
307
            if (isset($_GET['user']) && $_GET['user'] == $id) {
308
                echo 'selected="selected"';
309
            }
310
            echo '>'.$name.'</option>';
311
        }
312
        echo '</select>';
313
    }
314
315
    /**
316
     * @param int   $userId
317
     * @param array $survey_data
318
     * @param bool  $addMessage
319
     */
320
    public static function displayUserReportAnswers($userId, CSurvey $survey, $addMessage = true)
321
    {
322
        // Database table definitions
323
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
324
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
325
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
326
        $course_id = api_get_course_int_id();
327
        $surveyId = $survey->getIid();
328
        $userId = Database::escape_string($userId);
329
330
        $content = '';
331
        // Step 2: displaying the survey and the answer of the selected users
332
        if (!empty($userId)) {
333
            if ($addMessage) {
334
                $content .= Display::return_message(
335
                    get_lang('This screen displays an exact copy of the form as it was filled by the user'),
336
                    'normal',
337
                    false
338
                );
339
            }
340
341
            // Getting all the questions and options
342
            $sql = "SELECT
343
			            survey_question.iid question_id,
344
			            survey_question.survey_id,
345
			            survey_question.survey_question,
346
			            survey_question.display,
347
			            survey_question.max_value,
348
			            survey_question.sort,
349
			            survey_question.type,
350
                        survey_question_option.iid question_option_id,
351
                        survey_question_option.option_text,
352
                        survey_question_option.sort as option_sort
353
					FROM $table_survey_question survey_question
354
					LEFT JOIN $table_survey_question_option survey_question_option
355
					ON
356
					    survey_question.iid = survey_question_option.question_id
357
					WHERE
358
					    survey_question NOT LIKE '%{{%' AND
359
					    survey_question.survey_id = '".$surveyId."'
360
					ORDER BY survey_question.sort, survey_question_option.sort ASC";
361
            $result = Database::query($sql);
362
            while ($row = Database::fetch_array($result, 'ASSOC')) {
363
                if ('pagebreak' !== $row['type']) {
364
                    $questions[$row['sort']]['question_id'] = $row['question_id'];
365
                    $questions[$row['sort']]['survey_id'] = $row['survey_id'];
366
                    $questions[$row['sort']]['survey_question'] = $row['survey_question'];
367
                    $questions[$row['sort']]['display'] = $row['display'];
368
                    $questions[$row['sort']]['type'] = $row['type'];
369
                    $questions[$row['sort']]['maximum_score'] = $row['max_value'];
370
                    $questions[$row['sort']]['options'][$row['question_option_id']] = $row['option_text'];
371
                }
372
            }
373
374
            // Getting all the answers of the user
375
            $sql = "SELECT * FROM $table_survey_answer
376
			        WHERE
377
                        survey_id = '".$surveyId."' AND
378
                        user = '".$userId."'";
379
            $result = Database::query($sql);
380
            while ($row = Database::fetch_array($result, 'ASSOC')) {
381
                $answers[$row['question_id']][] = $row['option_id'];
382
                $all_answers[$row['question_id']][] = $row;
383
            }
384
385
            // Displaying all the questions
386
            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...
387
                // If the question type is a scoring then we have to format the answers differently
388
                switch ($question['type']) {
389
                    case 'score':
390
                        $finalAnswer = [];
391
                        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...
392
                            foreach ($all_answers[$question['question_id']] as $key => &$answer_array) {
393
                                $finalAnswer[$answer_array['option_id']] = $answer_array['value'];
394
                            }
395
                        }
396
                        break;
397
                    case 'multipleresponse':
398
                        $finalAnswer = isset($answers[$question['question_id']]) ? $answers[$question['question_id']] : '';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $answers does not seem to be defined for all execution paths leading up to this point.
Loading history...
399
                        break;
400
                    default:
401
                        $finalAnswer = '';
402
                        if (isset($all_answers[$question['question_id']])) {
403
                            $finalAnswer = $all_answers[$question['question_id']][0]['option_id'];
404
                        }
405
                        break;
406
                }
407
408
                $display = survey_question::createQuestion($question['type']);
409
                $url = api_get_self();
410
                $form = new FormValidator('question', 'post', $url);
411
                $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
412
                $form->addHtml($question['survey_question']);
413
                $display->render($form, $question, $finalAnswer);
414
                $form->addHtml('</div></div>');
415
                $content .= $form->returnForm();
416
            }
417
        }
418
419
        return $content;
420
    }
421
422
    /**
423
     * This function displays the user report which is basically nothing more
424
     * than a one-page display of all the questions
425
     * of the survey that is filled with the answers of the person who filled the survey.
426
     *
427
     * @return string html code of the one-page survey with the answers of the selected user
428
     *
429
     * @author Patrick Cool <[email protected]>, Ghent University
430
     *
431
     * @version February 2007 - Updated March 2008
432
     */
433
    public static function displayUserReport(CSurvey $survey, $people_filled, $addActionBar = true)
434
    {
435
        $surveyId = $survey->getIid();
436
        $reportingUrl = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
437
438
        // Actions bar
439
        if ($addActionBar) {
440
            echo '<div class="actions">';
441
            echo '<a href="'.$reportingUrl.'">'.
442
                Display::return_icon(
443
                    'back.png',
444
                    get_lang('Back to').' '.get_lang('Reporting overview'),
445
                    '',
446
                    ICON_SIZE_MEDIUM
447
                )
448
                .'</a>';
449
            if (isset($_GET['user'])) {
450
                if (api_is_allowed_to_edit()) {
451
                    // The delete link
452
                    echo '<a
453
                        href="'.$reportingUrl.'&action=deleteuserreport&user='.Security::remove_XSS($_GET['user']).'" >'.
454
                        Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_MEDIUM).'</a>';
455
                }
456
457
                // Export the user report
458
                echo '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
459
                    .Display::return_icon('export_csv.png', get_lang('CSV export'), '', ICON_SIZE_MEDIUM).'</a> ';
460
                echo '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
461
                    .Display::return_icon('export_excel.png', get_lang('Excel export'), '', ICON_SIZE_MEDIUM).'</a> ';
462
                echo '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
463
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
464
                    .Security::remove_XSS($_GET['user']).'">';
465
                echo '<input type="hidden" name="export_report" value="export_report">';
466
                echo '<input type="hidden" name="export_format" value="csv">';
467
                echo '</form>';
468
                echo '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
469
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
470
                    .Security::remove_XSS($_GET['user']).'">';
471
                echo '<input type="hidden" name="export_report" value="export_report">';
472
                echo '<input type="hidden" name="export_format" value="xls">';
473
                echo '</form>';
474
                echo '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
475
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
476
            }
477
            echo '</div>';
478
        }
479
480
        echo self::displayUserReportForm($survey, $people_filled);
481
        if (isset($_GET['user'])) {
482
            echo self::displayUserReportAnswers($_GET['user'], $survey);
483
        }
484
    }
485
486
    /**
487
     * This function displays the report by question.
488
     *
489
     * It displays a table with all the options of the question and the number of users who have answered positively on
490
     * the option. The number of users who answered positive on a given option is expressed in an absolute number, in a
491
     * percentage of the total and graphically using bars By clicking on the absolute number you get a list with the
492
     * persons who have answered this. You can then click on the name of the person and you will then go to the report
493
     * by user where you see all the answers of that user.
494
     *
495
     * @return string html code that displays the report by question
496
     *
497
     * @todo allow switching between horizontal and vertical.
498
     * @todo multiple response: percentage are probably not OK
499
     * @todo the question and option text have to be shortened and should expand when the user clicks on it.
500
     * @todo the pagebreak and comment question types should not be shown => removed from $survey_data before
501
     *
502
     * @author Patrick Cool <[email protected]>, Ghent University
503
     *
504
     * @version February 2007 - Updated March 2008
505
     */
506
    public static function display_question_report(CSurvey $survey)
507
    {
508
        $singlePage = isset($_GET['single_page']) ? (int) $_GET['single_page'] : 0;
509
        // Determining the offset of the sql statement (the n-th question of the survey)
510
        $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question'];
511
        $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0;
512
        $surveyId = $survey->getIid();
513
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
514
        $course_id = api_get_course_int_id();
515
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
516
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
517
518
        echo '<div class="actions">';
519
        echo '<a
520
            href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'.
521
            Display::return_icon(
522
                'back.png',
523
                get_lang('Back to').' '.get_lang('Reporting overview'),
524
                '',
525
                ICON_SIZE_MEDIUM
526
            ).'</a>';
527
        echo Display::url(
528
            Display::return_icon(
529
                'pdf.png',
530
                get_lang('ExportToPdf'),
531
                '',
532
                ICON_SIZE_MEDIUM
533
            ),
534
            'javascript: void(0);',
535
            ['onclick' => 'exportToPdf();']
536
        );
537
        echo '</div>';
538
        $fromUntil = sprintf(
539
            get_lang('FromXUntilY'),
540
            api_get_local_time($survey->getAvailFrom()),
541
            api_get_local_time($survey->getAvailTill())
542
        );
543
        $max = 80;
544
        $data = [
545
            get_lang('SurveyTitle') => cut(strip_tags($survey->getTitle()), $max),
546
            get_lang('SurveySubTitle') => cut(strip_tags($survey->getSubtitle()), $max),
547
            get_lang('Dates') => $fromUntil,
548
            get_lang('SurveyIntroduction') => cut(strip_tags($survey->getIntro()), $max),
549
        ];
550
551
        $table = new HTML_Table(['id' => 'pdf_table', 'class' => 'table']);
552
        $row = 0;
553
        foreach ($data as $label => $item) {
554
            $table->setCellContents($row, 0, $label);
555
            $table->setCellContents($row, 1, $item);
556
            $row++;
557
        }
558
559
        $questions = $survey->getQuestions();
560
        $numberOfQuestions = 0;
561
        foreach ($questions as $question) {
562
            if ('pagebreak' !== $question->getType()) {
563
                $numberOfQuestions++;
564
            }
565
        }
566
567
        $newQuestionList = [];
568
        if ($numberOfQuestions > 0) {
569
            $limitStatement = null;
570
            if (!$singlePage) {
571
                echo '<div id="question_report_questionnumbers" class="pagination">';
572
                if (0 != $currentQuestion) {
573
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
574
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset - 1).'">'
575
                        .get_lang('Previous question').'</a></li>';
576
                }
577
578
                for ($i = 1; $i <= $numberOfQuestions; $i++) {
579
                    if ($offset != $i - 1) {
580
                        echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
581
                            .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($i - 1).'">'.$i.'</a></li>';
582
                    } else {
583
                        echo '<li class="disabled"s><a href="#">'.$i.'</a></li>';
584
                    }
585
                }
586
                if ($currentQuestion < ($numberOfQuestions - 1)) {
587
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
588
                        .api_get_cidreq().'&survey_id='.$surveyId.'&question='.($offset + 1).'">'
589
                        .get_lang('Next question').'</li></a>';
590
                }
591
                echo '</ul>';
592
                echo '</div>';
593
                $limitStatement = " LIMIT $offset, 1";
594
            }
595
596
            // Getting the question information
597
            /*$sql = "SELECT * FROM $table_survey_question
598
			        WHERE
599
                        survey_id = $surveyId AND
600
                        survey_question NOT LIKE '%{{%' AND
601
                        type <>'pagebreak'
602
                    ORDER BY sort ASC
603
                    $limitStatement";
604
            $result = Database::query($sql);
605
            while ($row = Database::fetch_array($result)) {*/
606
            foreach ($questions as $question) {
607
                if (strpos($question->getSurveyQuestion(), '%{{%') && 'pagebreak' !== $question->getType()) {
608
                    continue;
609
                }
610
                $newQuestionList[$question->getIid()] = $question;
611
            }
612
        }
613
        echo '<div id="question_results">';
614
        /** @var CSurveyQuestion $question */
615
        foreach ($newQuestionList as $question) {
616
            $chartData = [];
617
            $options = [];
618
            $questionId = $question->getIid();
619
620
            echo '<div class="question-item">';
621
            echo '<div class="title-question">';
622
            echo strip_tags($question->getSurveyQuestion());
623
            echo '</div>';
624
            $type = $question->getType();
625
626
            if ('score' === $type) {
627
                /** @todo This function should return the options as this is needed further in the code */
628
                $options = self::display_question_report_score($survey, $question, $offset);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $options is correct as self::display_question_r...ey, $question, $offset) targeting SurveyUtil::display_question_report_score() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
629
            } elseif ('open' === $type || 'comment' === $type) {
630
                echo '<div class="open-question">';
631
                /** @todo Also get the user who has answered this */
632
                $sql = "SELECT * FROM $table_survey_answer
633
                        WHERE
634
                            survey_id= $surveyId AND
635
                            question_id = $questionId ";
636
                $result = Database::query($sql);
637
                while ($row = Database::fetch_array($result, 'ASSOC')) {
638
                    echo $row['option_id'].'<hr noshade="noshade" size="1" />';
639
                }
640
                echo '</div>';
641
            } else {
642
                // Getting the options ORDER BY sort ASC
643
                $sql = "SELECT * FROM $table_survey_question_option
644
                        WHERE
645
                            survey_id = $surveyId AND
646
                            question_id = $questionId
647
                        ORDER BY sort ASC";
648
                $result = Database::query($sql);
649
                while ($row = Database::fetch_array($result, 'ASSOC')) {
650
                    $options[$row['iid']] = $row;
651
                }
652
                // Getting the answers
653
                $sql = "SELECT *, count(iid) as total
654
                        FROM $table_survey_answer
655
                        WHERE
656
                            survey_id = $surveyId AND
657
                            question_id = $questionId
658
                        GROUP BY option_id, value";
659
                $result = Database::query($sql);
660
                $number_of_answers = [];
661
                $data = [];
662
                while ($row = Database::fetch_array($result, 'ASSOC')) {
663
                    if (!isset($number_of_answers[$row['question_id']])) {
664
                        $number_of_answers[$row['question_id']] = 0;
665
                    }
666
                    $number_of_answers[$row['question_id']] += $row['total'];
667
                    if ('multiplechoiceother' === $type) {
668
                        $parts = ch_multiplechoiceother::decodeOptionValue($row['option_id']);
669
                        $row['option_id'] = $parts[0];
670
                    }
671
                    $data[$row['option_id']] = $row;
672
                }
673
674
                foreach ($options as $option) {
675
                    $optionText = strip_tags($option['option_text']);
676
                    $optionText = html_entity_decode($optionText);
677
                    $votes = 0;
678
                    if (isset($data[$option['iid']]['total'])) {
679
                        $votes = $data[$option['iid']]['total'];
680
                    }
681
                    array_push($chartData, ['option' => $optionText, 'votes' => $votes]);
682
                }
683
                $chartContainerId = 'chartContainer'.$questionId;
684
                echo '<div id="'.$chartContainerId.'" style="text-align:center;">';
685
                echo self::drawChart($chartData, false, $chartContainerId, false);
686
                echo '</div>';
687
688
                // displaying the table: headers
689
                echo '<table class="display-survey table" id="table_'.$chartContainerId.'">';
690
                echo '';
691
                echo '	<tr>';
692
                echo '		<th style="width: 50%">&nbsp;</th>';
693
                echo '		<th style="width: 10%">'.get_lang('AbsoluteTotal').'</th>';
694
                echo '		<th style="width: 10%">'.get_lang('Percentage').'</th>';
695
                echo '		<th style="width: 30%">'.get_lang('VisualRepresentation').'</th>';
696
                echo '	</tr>';
697
698
                // Displaying the table: the content
699
                if (is_array($options)) {
700
                    foreach ($options as $key => &$value) {
701
                        if ('multiplechoiceother' === $type && 'other' === $value['option_text']) {
702
                            $value['option_text'] = get_lang('SurveyOtherAnswer');
703
                        }
704
705
                        $absolute_number = null;
706
                        if (isset($data[$value['iid']])) {
707
                            $absolute_number = $data[$value['iid']]['total'];
708
                        }
709
                        if ('percentage' === $type && empty($absolute_number)) {
710
                            continue;
711
                        }
712
                        $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...
713
                            ? $number_of_answers[$option['question_id']]
714
                            : 0;
715
                        if (0 == $number_of_answers[$option['question_id']]) {
716
                            $answers_number = 0;
717
                        } else {
718
                            $answers_number = $absolute_number / $number_of_answers[$option['question_id']] * 100;
719
                        }
720
                        echo '	<tr>';
721
                        echo '<td>'.$value['option_text'].'</td>';
722
                        echo '<td>';
723
                        if (0 != $absolute_number) {
724
                            echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
725
                                .'&survey_id='.$surveyId.'&question='.$offset.'&viewoption='
726
                                .$value['iid'].'">'.$absolute_number.'</a>';
727
                        } else {
728
                            echo '0';
729
                        }
730
731
                        echo '      </td>';
732
                        echo '<td>'.round($answers_number, 2).' %</td>';
733
                        echo '<td>';
734
                        $size = $answers_number * 2;
735
                        if ($size > 0) {
736
                            echo '<div
737
                                    style="border:1px solid #264269; background-color:#aecaf4; height:10px;
738
                                    width:'.$size.'px">
739
                                    &nbsp;
740
                                    </div>';
741
                        } else {
742
                            echo '<div style="text-align: left;">'.get_lang("No data available").'</div>';
743
                        }
744
                        echo ' </td>';
745
                        echo ' </tr>';
746
                    }
747
                }
748
749
                $optionResult = '';
750
                if (isset($option['question_id']) && isset($number_of_answers[$option['question_id']])) {
751
                    if (0 == $number_of_answers[$option['question_id']]) {
752
                        $optionResult = '0';
753
                    } else {
754
                        $optionResult = $number_of_answers[$option['question_id']];
755
                    }
756
                }
757
758
                // displaying the table: footer (totals)
759
                echo '	<tr>
760
                            <td><b>'.get_lang('Total').'</b></td>
761
                            <td><b>'.$optionResult.'</b></td>
762
                            <td>&nbsp;</td>
763
                            <td>&nbsp;</td>
764
                        </tr>
765
                        </table>';
766
            }
767
            echo '</div>';
768
        }
769
        echo '</div>';
770
771
        // Survey information, needed for the PDF export.
772
        echo Display::page_subheader(get_lang('Survey')).'<br />';
773
        $table->display();
774
775
        if (isset($_GET['viewoption'])) {
776
            echo '<div class="answered-people">';
777
            echo '<h4>'.get_lang('People who have chosen this answer').': '
778
                .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 615. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
779
780
            if (is_numeric($_GET['value'])) {
781
                $sql_restriction = "AND value='".Database::escape_string($_GET['value'])."'";
782
            }
783
784
            $sql = "SELECT user FROM $table_survey_answer
785
                    WHERE
786
                        c_id = $course_id AND
787
                        option_id = '".Database::escape_string($_GET['viewoption'])."'
788
                        $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...
789
            $result = Database::query($sql);
790
            echo '<ul>';
791
            while ($row = Database::fetch_array($result, 'ASSOC')) {
792
                $user_info = api_get_user_info($row['user']);
793
                echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
794
                    .$surveyId.'&user='.$row['user'].'">'
795
                    .$user_info['complete_name_with_username']
796
                    .'</a></li>';
797
            }
798
            echo '</ul>';
799
            echo '</div>';
800
        }
801
    }
802
803
    /**
804
     * Display score data about a survey question.
805
     *
806
     * @param    int    The offset of results shown
807
     */
808
    public static function display_question_report_score(CSurvey $survey, CSurveyQuestion $question, $offset)
809
    {
810
        // Database table definitions
811
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
812
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
813
        $surveyId = $survey->getIid();
814
        $questionId = $question->getIid();
815
        $options = $survey->getOptions();
816
        // Getting the options
817
        /*$sql = "SELECT * FROM $table_survey_question_option
818
                WHERE
819
                    survey_id= $surveyId AND
820
                    question_id = '".intval($question['iid'])."'
821
                ORDER BY sort ASC";
822
        $result = Database::query($sql);
823
        while ($row = Database::fetch_array($result)) {*/
824
        foreach ($options as $option) {
825
            $options[$option->getIid()] = $option;
826
        }
827
828
        // Getting the answers
829
        $sql = "SELECT *, count(iid) as total
830
                FROM $table_survey_answer
831
                WHERE
832
                   survey_id= $surveyId AND
833
                   question_id = '".$questionId."'
834
                GROUP BY option_id, value";
835
        $result = Database::query($sql);
836
        $number_of_answers = 0;
837
        while ($row = Database::fetch_array($result)) {
838
            $number_of_answers += $row['total'];
839
            $data[$row['option_id']][$row['value']] = $row;
840
        }
841
842
        $chartData = [];
843
        /** @var CSurveyQuestionOption $option */
844
        foreach ($options as $option) {
845
            $optionId = $option->getIid();
846
            $optionText = strip_tags($option->getOptionText());
847
            $optionText = html_entity_decode($optionText);
848
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
849
                $votes = null;
850
                if (isset($data[$optionId][$i])) {
851
                    $votes = $data[$optionId][$i]['total'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.
Loading history...
852
                }
853
854
                if (empty($votes)) {
855
                    $votes = '0';
856
                }
857
                array_push(
858
                    $chartData,
859
                    [
860
                        'serie' => $optionText,
861
                        'option' => $i,
862
                        'votes' => $votes,
863
                    ]
864
                );
865
            }
866
        }
867
        echo '<div id="chartContainer" class="col-md-12">';
868
        echo self::drawChart($chartData, true);
869
        echo '</div>';
870
871
        // Displaying the table: headers
872
        echo '<table class="table">';
873
        echo '	<tr>';
874
        echo '		<th>&nbsp;</th>';
875
        echo '		<th>'.get_lang('Score').'</th>';
876
        echo '		<th>'.get_lang('Absolute total').'</th>';
877
        echo '		<th>'.get_lang('Percentage').'</th>';
878
        echo '		<th>'.get_lang('Graphic').'</th>';
879
        echo '	</tr>';
880
        // Displaying the table: the content
881
        foreach ($options as $key => $value) {
882
            $optionId = $value->getIid();
883
            for ($i = 1; $i <= $question->getMaxValue(); $i++) {
884
                $absolute_number = null;
885
                if (isset($data[$optionId][$i])) {
886
                    $absolute_number = $data[$optionId][$i]['total'];
887
                }
888
889
                echo '<tr>';
890
                echo '<td>'.$value->getOptionText().'</td>';
891
                echo '<td>'.$i.'</td>';
892
893
                echo '<td><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action
894
                    .'&survey_id='.$surveyId.'&question='.Security::remove_XSS($offset)
895
                    .'&viewoption='.$optionId.'&value='.$i.'">'.$absolute_number.'</a></td>';
896
897
                $percentage = 0;
898
                $size = 0;
899
                if (!empty($number_of_answers)) {
900
                    $percentage = round($absolute_number / $number_of_answers * 100, 2);
901
                    $size = ($absolute_number / $number_of_answers * 100 * 2);
902
                }
903
                echo '<td>'.$percentage.' %</td>';
904
                echo '<td>';
905
                if ($size > 0) {
906
                    echo '<div
907
                            style="border:1px solid #264269;
908
                            background-color:#aecaf4;
909
                            height:10px; width:'.$size.'px">
910
                            &nbsp;
911
                        </div>';
912
                }
913
                echo '		</td>';
914
                echo '	</tr>';
915
            }
916
        }
917
        // Displaying the table: footer (totals)
918
        echo '	<tr>';
919
        echo '		<td style="border-top:1px solid black"><b>'.get_lang('Total').'</b></td>';
920
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
921
        echo '		<td style="border-top:1px solid black"><b>'.$number_of_answers.'</b></td>';
922
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
923
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
924
        echo '	</tr>';
925
        echo '</table>';
926
    }
927
928
    /**
929
     * This functions displays the complete reporting.
930
     *
931
     * @param int   $userId
932
     * @param bool  $addActionBar
933
     * @param bool  $addFilters
934
     * @param bool  $addExtraFields
935
     *
936
     * @return string
937
     */
938
    public static function displayCompleteReport(
939
        CSurvey $survey,
940
        $userId = 0,
941
        $addActionBar = true,
942
        $addFilters = true,
943
        $addExtraFields = true
944
    ) {
945
        // Database table definitions
946
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
947
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
948
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
949
950
        $surveyId = $survey->getIid();
951
        $course_id = api_get_course_int_id();
952
953
        if (empty($surveyId) || empty($course_id)) {
954
            return '';
955
        }
956
957
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
958
        $content = '';
959
        if ($addActionBar) {
960
            $content .= '<div class="actions">';
961
            $content .= '<a
962
                href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
963
                .Display::return_icon(
964
                    'back.png',
965
                    get_lang('Back to').' '.get_lang('Reporting overview'),
966
                    [],
967
                    ICON_SIZE_MEDIUM
968
                )
969
                .'</a>';
970
            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
971
                .Display::return_icon('export_csv.png', get_lang('CSV export'), '', ICON_SIZE_MEDIUM).'</a>';
972
            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
973
                .Display::return_icon('export_excel.png', get_lang('Excel export'), '', ICON_SIZE_MEDIUM).'</a>';
974
            $content .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1c.submit();">'
975
                .Display::return_icon('export_compact_csv.png', get_lang('ExportAsCompactCSV'), '', ICON_SIZE_MEDIUM).'</a>';
976
            $content .= '</div>';
977
978
            // The form
979
            $content .= '<form id="form1a" name="form1a" method="post" action="'.api_get_self(
980
                ).'?action='.$action.'&survey_id='
981
                .$surveyId.'&'.api_get_cidreq().'">';
982
            $content .= '<input type="hidden" name="export_report" value="export_report">';
983
            $content .= '<input type="hidden" name="export_format" value="csv">';
984
            $content .= '</form>';
985
            $content .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self(
986
                ).'?action='.$action.'&survey_id='
987
                .$surveyId.'&'.api_get_cidreq().'">';
988
            $content .= '<input type="hidden" name="export_report" value="export_report">';
989
            $content .= '<input type="hidden" name="export_format" value="xls">';
990
            $content .= '</form>';
991
            $content .= '<form id="form1c" name="form1c" method="post" action="'.api_get_self(
992
                ).'?action='.$action.'&survey_id='
993
                .$surveyId.'&'.api_get_cidreq().'">';
994
            $content .= '<input type="hidden" name="export_report" value="export_report">';
995
            $content .= '<input type="hidden" name="export_format" value="csv-compact">';
996
            $content .= '</form>';
997
        }
998
999
        $content .= '<form
1000
            id="form2"
1001
            name="form2"
1002
            method="post"
1003
            action="'.api_get_self().'?action='.$action.'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
1004
        $content .= '<br /><table class="table table-hover table-striped data_table" border="1">';
1005
        // Getting the number of options per question
1006
        $content .= '<tr>';
1007
        $content .= '<th>';
1008
1009
        if ($addFilters) {
1010
            if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1011
                (isset($_POST['export_report']) && $_POST['export_report'])
1012
            ) {
1013
                $content .= '<button class="cancel"
1014
                                type="submit"
1015
                                name="reset_question_filter" value="'.get_lang('Reset filter').'">'.
1016
                                get_lang('Reset filter').'</button>';
1017
            }
1018
            $content .= '<button
1019
                            class = "save"
1020
                            type="submit" name="submit_question_filter" value="'.get_lang('Filter').'">'.
1021
                            get_lang('Filter').'</button>';
1022
            $content .= '</th>';
1023
        }
1024
1025
        $display_extra_user_fields = false;
1026
        if ($addExtraFields) {
1027
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1028
                    isset($_POST['export_report']) && $_POST['export_report']) ||
1029
                !empty($_POST['fields_filter'])
1030
            ) {
1031
                // Show user fields section with a big th colspan that spans over all fields
1032
                $extra_user_fields = UserManager::get_extra_fields(
1033
                    0,
1034
                    0,
1035
                    5,
1036
                    'ASC',
1037
                    false,
1038
                    true
1039
                );
1040
                $num = count($extra_user_fields);
1041
                if ($num > 0) {
1042
                    $content .= '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
1043
                    $content .= '<label>';
1044
                    if ($addFilters) {
1045
                        $content .= '<input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
1046
                    }
1047
                    $content .= get_lang('Profile attributes');
1048
                    $content .= '</label>';
1049
                    $content .= '</th>';
1050
                    $display_extra_user_fields = true;
1051
                }
1052
            }
1053
        }
1054
1055
        $sql = "SELECT
1056
                  q.iid question_id,
1057
                  q.type,
1058
                  q.survey_question,
1059
                  count(o.iid) as number_of_options
1060
				FROM $table_survey_question q
1061
				LEFT JOIN $table_survey_question_option o
1062
				ON q.iid = o.question_id
1063
				WHERE
1064
				    survey_question NOT LIKE '%{{%' AND
1065
				    q.survey_id = '".$surveyId."'
1066
				GROUP BY q.iid
1067
				ORDER BY q.sort ASC";
1068
        $result = Database::query($sql);
1069
        $questions = [];
1070
        while ($row = Database::fetch_array($result)) {
1071
            // We show the questions if
1072
            // 1. there is no question filter and the export button has not been clicked
1073
            // 2. there is a quesiton filter but the question is selected for display
1074
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1075
                (is_array($_POST['questions_filter']) &&
1076
                in_array($row['question_id'], $_POST['questions_filter']))
1077
            ) {
1078
                // We do not show comment and pagebreak question types
1079
                if ('pagebreak' !== $row['type']) {
1080
                    $content .= ' <th';
1081
                    if ($row['number_of_options'] > 0 && 'percentage' !== $row['type']) {
1082
                        $content .= ' colspan="'.$row['number_of_options'].'"';
1083
                    }
1084
                    $content .= '>';
1085
                    $content .= '<label>';
1086
                    if ($addFilters) {
1087
                        $content .= '<input
1088
                                type="checkbox"
1089
                                name="questions_filter[]" value="'.$row['question_id'].'" checked="checked"/>';
1090
                    }
1091
                    $content .= $row['survey_question'];
1092
                    $content .= '</label>';
1093
                    $content .= '</th>';
1094
                }
1095
                // No column at all if it's not a question
1096
            }
1097
            $questions[$row['question_id']] = $row;
1098
        }
1099
        $content .= '	</tr>';
1100
1101
        // Getting all the questions and options
1102
        $content .= '	<tr>';
1103
        $content .= '		<th>&nbsp;</th>'; // the user column
1104
1105
        if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1106
            isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter'])
1107
        ) {
1108
            if ($addExtraFields) {
1109
                // show the fields names for user fields
1110
                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...
1111
                    $content .= '<th>'.$field[3].'</th>';
1112
                }
1113
            }
1114
        }
1115
1116
        // cells with option (none for open question)
1117
        $sql = "SELECT
1118
                    sq.iid question_id,
1119
                    sq.survey_id,
1120
                    sq.survey_question,
1121
                    sq.display,
1122
                    sq.sort,
1123
                    sq.type,
1124
                    sqo.iid question_option_id,
1125
                    sqo.option_text,
1126
                    sqo.sort as option_sort
1127
				FROM $table_survey_question sq
1128
				LEFT JOIN $table_survey_question_option sqo
1129
				ON sq.iid = sqo.question_id
1130
				WHERE
1131
				    survey_question NOT LIKE '%{{%' AND
1132
				    sq.survey_id = $surveyId
1133
				ORDER BY sq.sort ASC, sqo.sort ASC";
1134
        $result = Database::query($sql);
1135
1136
        $display_percentage_header = 1;
1137
        $possible_answers = [];
1138
        // in order to display only once the cell option (and not 100 times)
1139
        while ($row = Database::fetch_array($result)) {
1140
            // We show the options if
1141
            // 1. there is no question filter and the export button has not been clicked
1142
            // 2. there is a question filter but the question is selected for display
1143
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1144
                (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']))
1145
            ) {
1146
                // we do not show comment and pagebreak question types
1147
                if ('open' == $row['type'] || 'comment' == $row['type']) {
1148
                    $content .= '<th>&nbsp;-&nbsp;</th>';
1149
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1150
                    $display_percentage_header = 1;
1151
                } elseif ('percentage' == $row['type'] && $display_percentage_header) {
1152
                    $content .= '<th>&nbsp;%&nbsp;</th>';
1153
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1154
                    $display_percentage_header = 0;
1155
                } elseif ('percentage' == $row['type']) {
1156
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1157
                } elseif ('pagebreak' != $row['type'] && 'percentage' != $row['type']) {
1158
                    $content .= '<th>';
1159
                    $content .= $row['option_text'];
1160
                    $content .= '</th>';
1161
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1162
                    $display_percentage_header = 1;
1163
                }
1164
            }
1165
        }
1166
1167
        $content .= '	</tr>';
1168
1169
        $userCondition = '';
1170
        if (!empty($userId)) {
1171
            $userId = (int) $userId;
1172
            $userCondition = " AND user = $userId ";
1173
        }
1174
1175
        // Getting all the answers of the users
1176
        $old_user = '';
1177
        $answers_of_user = [];
1178
        $sql = "SELECT * FROM $table_survey_answer
1179
                WHERE
1180
                    survey_id = $surveyId
1181
                    $userCondition
1182
                ORDER BY iid, user ASC";
1183
        $result = Database::query($sql);
1184
        $i = 1;
1185
        while ($row = Database::fetch_array($result)) {
1186
            if ($old_user != $row['user'] && '' != $old_user) {
1187
                $userParam = $old_user;
1188
                if (0 != $survey->getAnonymous()) {
1189
                    $userParam = $i;
1190
                    $i++;
1191
                }
1192
                $content .= self::display_complete_report_row(
1193
                    $survey,
1194
                    $possible_answers,
1195
                    $answers_of_user,
1196
                    $userParam,
1197
                    $questions,
1198
                    $display_extra_user_fields
1199
                );
1200
                $answers_of_user = [];
1201
            }
1202
            if (isset($questions[$row['question_id']]) &&
1203
                'open' != $questions[$row['question_id']]['type'] &&
1204
                'comment' != $questions[$row['question_id']]['type']
1205
            ) {
1206
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1207
            } else {
1208
                $answers_of_user[$row['question_id']][0] = $row;
1209
            }
1210
            $old_user = $row['user'];
1211
        }
1212
1213
        $userParam = $old_user;
1214
        if (0 != $survey->getAnonymous()) {
1215
            $userParam = $i;
1216
            $i++;
1217
        }
1218
1219
        $content .= self::display_complete_report_row(
1220
            $survey,
1221
            $possible_answers,
1222
            $answers_of_user,
1223
            $userParam,
1224
            $questions,
1225
            $display_extra_user_fields
1226
        );
1227
1228
        // This is to display the last user
1229
        $content .= '</table>';
1230
        $content .= '</form>';
1231
1232
        return $content;
1233
    }
1234
1235
    /**
1236
     * Return user answers in a row.
1237
     *
1238
     * @return string
1239
     */
1240
    public static function display_complete_report_row(
1241
        CSurvey $survey,
1242
        $possible_options,
1243
        $answers_of_user,
1244
        $user,
1245
        $questions,
1246
        $display_extra_user_fields = false
1247
    ) {
1248
        $user = Security::remove_XSS($user);
1249
        $surveyId = $survey->getIid();
1250
1251
        if (empty($surveyId)) {
1252
            return '';
1253
        }
1254
1255
        $content = '<tr>';
1256
        $url = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
1257
        if (0 == $survey->getAnonymous()) {
1258
            if (0 !== (int) $user) {
1259
                $userInfo = api_get_user_info($user);
1260
                $user_displayed = '-';
1261
                if (!empty($userInfo)) {
1262
                    $user_displayed = $userInfo['complete_name_with_username'];
1263
                }
1264
1265
                $content .= '<th>
1266
                    <a href="'.$url.'&action=userreport&user='.$user.'">'
1267
                        .$user_displayed.'
1268
                    </a>
1269
                    </th>'; // the user column
1270
            } else {
1271
                $content .= '<th>'.$user.'</th>'; // the user column
1272
            }
1273
        } else {
1274
            $content .= '<th>'.get_lang('Anonymous').' '.$user.'</th>';
1275
        }
1276
1277
        if ($display_extra_user_fields) {
1278
            // Show user fields data, if any, for this user
1279
            $user_fields_values = UserManager::get_extra_user_data(
1280
                $user,
1281
                false,
1282
                false,
1283
                false,
1284
                true
1285
            );
1286
            foreach ($user_fields_values as &$value) {
1287
                $content .= '<td align="center">'.$value.'</td>';
1288
            }
1289
        }
1290
1291
        if (is_array($possible_options)) {
1292
            foreach ($possible_options as $question_id => &$possible_option) {
1293
                if ('open' === $questions[$question_id]['type'] || 'comment' === $questions[$question_id]['type']) {
1294
                    $content .= '<td align="center">';
1295
                    if (isset($answers_of_user[$question_id]) && isset($answers_of_user[$question_id]['0'])) {
1296
                        $content .= $answers_of_user[$question_id]['0']['option_id'];
1297
                    }
1298
                    $content .= '</td>';
1299
                } else {
1300
                    foreach ($possible_option as $option_id => $value) {
1301
                        if ('multiplechoiceother' === $questions[$question_id]['type']) {
1302
                            foreach ($answers_of_user[$question_id] as $key => $newValue) {
1303
                                $parts = ch_multiplechoiceother::decodeOptionValue($key);
1304
                                if (isset($parts[0])) {
1305
                                    $data = $answers_of_user[$question_id][$key];
1306
                                    unset($answers_of_user[$question_id][$key]);
1307
                                    $newKey = $parts[0];
1308
                                    $answers_of_user[$question_id][$newKey] = $data;
1309
                                }
1310
                            }
1311
                        }
1312
                        if ('percentage' === $questions[$question_id]['type']) {
1313
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1314
                                $content .= "<td align='center'>";
1315
                                $content .= $answers_of_user[$question_id][$option_id]['value'];
1316
                                $content .= "</td>";
1317
                            }
1318
                        } else {
1319
                            $content .= '<td align="center">';
1320
                            if (!empty($answers_of_user[$question_id][$option_id])) {
1321
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1322
                                    $content .= $answers_of_user[$question_id][$option_id]['value'];
1323
                                } else {
1324
                                    $content .= 'v';
1325
                                }
1326
                            }
1327
                        }
1328
                    }
1329
                }
1330
            }
1331
        }
1332
1333
        $content .= '</tr>';
1334
1335
        return $content;
1336
    }
1337
1338
    /**
1339
     * Quite similar to display_complete_report(), returns an HTML string
1340
     * that can be used in a csv file.
1341
     *
1342
     * @param array $survey_data The basic survey data as initially obtained by SurveyManager::get_survey()
1343
     * @param int   $user_id     The ID of the user asking for the report
1344
     * @param bool  $compact     Whether to present the long (v marks with multiple columns per question) or compact
1345
     *                           (one column per question) answers format
1346
     *
1347
     * @todo consider merging this function with display_complete_report
1348
     *
1349
     * @throws Exception
1350
     *
1351
     * @return string The contents of a csv file
1352
     *
1353
     * @author Patrick Cool <[email protected]>, Ghent University
1354
     *
1355
     * @version February 2007
1356
     */
1357
    public static function export_complete_report($survey_data, $user_id = 0, $compact = false)
1358
    {
1359
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
1360
1361
        if (empty($surveyId)) {
1362
            return false;
1363
        }
1364
1365
        $course = api_get_course_info();
1366
        $course_id = $course['real_id'];
1367
1368
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1369
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1370
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1371
1372
        $translate = false;
1373
        if (true == api_get_configuration_value('translate_html')) {
1374
            $translate = true;
1375
        }
1376
1377
        // The first column
1378
        $return = ';';
1379
1380
        // Show extra fields blank space (enough for extra fields on next line)
1381
        $extra_user_fields = UserManager::get_extra_fields(
1382
            0,
1383
            0,
1384
            5,
1385
            'ASC',
1386
            false,
1387
            true
1388
        );
1389
1390
        $num = count($extra_user_fields);
1391
        $return .= str_repeat(';', $num);
1392
1393
        $sql = "SELECT
1394
                    questions.iid,
1395
                    questions.type,
1396
                    questions.survey_question,
1397
                    count(options.iid) as number_of_options
1398
				FROM $table_survey_question questions
1399
                LEFT JOIN $table_survey_question_option options
1400
				ON
1401
				  questions.iid = options.question_id
1402
				WHERE
1403
				    survey_question NOT LIKE '%{{%' AND
1404
				    questions.type <> 'pagebreak' AND
1405
				    questions.survey_id = $surveyId
1406
				GROUP BY questions.iid
1407
				ORDER BY questions.sort ASC";
1408
1409
        $result = Database::query($sql);
1410
        while ($row = Database::fetch_array($result)) {
1411
            if ($translate) {
1412
                $row['survey_question'] = api_get_filtered_multilingual_HTML_string($row['survey_question'], $course['language']);
1413
            }
1414
            // We show the questions if
1415
            // 1. there is no question filter and the export button has not been clicked
1416
            // 2. there is a quesiton filter but the question is selected for display
1417
            if (!(isset($_POST['submit_question_filter'])) ||
1418
                (isset($_POST['submit_question_filter']) &&
1419
                    is_array($_POST['questions_filter']) &&
1420
                    in_array($row['iid'], $_POST['questions_filter']))
1421
            ) {
1422
                if (0 == $row['number_of_options'] || $compact) {
1423
                    $return .= str_replace(
1424
                        "\r\n",
1425
                        '  ',
1426
                        api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1427
                    )
1428
                    .';';
1429
                } else {
1430
                    for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1431
                        $return .= str_replace(
1432
                            "\r\n",
1433
                            '  ',
1434
                            api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)
1435
                        )
1436
                        .';';
1437
                    }
1438
                }
1439
            }
1440
        }
1441
1442
        $return .= "\n";
1443
        // Getting all the questions and options
1444
        $return .= ';';
1445
        // Show the fields names for user fields
1446
        if (!empty($extra_user_fields)) {
1447
            foreach ($extra_user_fields as &$field) {
1448
                if ($translate) {
1449
                    $field[3] = api_get_filtered_multilingual_HTML_string($field[3], $course['language']);
1450
                }
1451
                $return .= '"'
1452
                    .str_replace(
1453
                        "\r\n",
1454
                        '  ',
1455
                        api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES)
1456
                    )
1457
                    .'";';
1458
            }
1459
        }
1460
1461
        $sql = "SELECT DISTINCT
1462
		            survey_question.iid question_id,
1463
		            survey_question.survey_id,
1464
		            survey_question.survey_question,
1465
		            survey_question.display,
1466
		            survey_question.sort,
1467
		            survey_question.type,
1468
                    survey_question_option.iid question_option_id,
1469
                    survey_question_option.option_text,
1470
                    survey_question_option.sort as option_sort
1471
				FROM $table_survey_question survey_question
1472
				LEFT JOIN $table_survey_question_option survey_question_option
1473
				ON
1474
				    survey_question.iid = survey_question_option.question_id
1475
				WHERE
1476
				    survey_question NOT LIKE '%{{%' AND
1477
				    survey_question.type <> 'pagebreak' AND
1478
				    survey_question.survey_id = $surveyId
1479
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1480
        $result = Database::query($sql);
1481
        $possible_answers = [];
1482
        $possible_answers_type = [];
1483
        while ($row = Database::fetch_array($result)) {
1484
            // We show the options if
1485
            // 1. there is no question filter and the export button has not been clicked
1486
            // 2. there is a question filter but the question is selected for display
1487
            if ($translate) {
1488
                $row['option_text'] = api_get_filtered_multilingual_HTML_string($row['option_text'], $course['language']);
1489
            }
1490
            if (!(isset($_POST['submit_question_filter'])) || (
1491
                is_array($_POST['questions_filter']) &&
1492
                in_array($row['question_id'], $_POST['questions_filter'])
1493
            )
1494
            ) {
1495
                $row['option_text'] = str_replace(["\r", "\n"], ['', ''], $row['option_text']);
1496
                if (!$compact) {
1497
                    $return .= api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES).';';
1498
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1499
                } else {
1500
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['option_text'];
1501
                }
1502
                $possible_answers_type[$row['question_id']] = $row['type'];
1503
            }
1504
        }
1505
1506
        $return .= "\n";
1507
1508
        // Getting all the answers of the users
1509
        $old_user = '';
1510
        $answers_of_user = [];
1511
        $sql = "SELECT * FROM $table_survey_answer
1512
		        WHERE
1513
		          survey_id = $surveyId
1514
		          ";
1515
        if (0 != $user_id) {
1516
            $user_id = (int) $user_id;
1517
            $sql .= " AND user = $user_id ";
1518
        }
1519
        $sql .= ' ORDER BY user ASC ';
1520
1521
        $questionIdList = array_keys($possible_answers_type);
1522
        $open_question_iterator = 1;
1523
        $result = Database::query($sql);
1524
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1525
            if (!in_array($row['question_id'], $questionIdList)) {
1526
                continue;
1527
            }
1528
            if ($old_user != $row['user'] && '' != $old_user) {
1529
                $return .= self::export_complete_report_row(
1530
                    $survey_data,
1531
                    $possible_answers,
1532
                    $answers_of_user,
1533
                    $old_user,
1534
                    true,
1535
                    $compact
1536
                );
1537
                $answers_of_user = [];
1538
            }
1539
1540
            if ('open' === $possible_answers_type[$row['question_id']] ||
1541
                'comment' === $possible_answers_type[$row['question_id']]
1542
            ) {
1543
                $temp_id = 'open'.$open_question_iterator;
1544
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1545
                $open_question_iterator++;
1546
            } else {
1547
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1548
            }
1549
            $old_user = $row['user'];
1550
        }
1551
1552
        // This is to display the last user
1553
        $return .= self::export_complete_report_row(
1554
            $survey_data,
1555
            $possible_answers,
1556
            $answers_of_user,
1557
            $old_user,
1558
            true,
1559
            $compact
1560
        );
1561
1562
        return $return;
1563
    }
1564
1565
    /**
1566
     * Add a line to the csv file.
1567
     *
1568
     * @param array $survey_data               Basic survey data (we're mostly interested in the 'anonymous' index)
1569
     * @param array $possible_options          Possible answers
1570
     * @param array $answers_of_user           User's answers
1571
     * @param mixed $user                      User ID or user details as string - Used as a string in the result
1572
     *                                         string
1573
     * @param bool  $display_extra_user_fields Whether to display user fields or not
1574
     * @param bool  $compact                   Whether to show answers as different column values (true) or one column
1575
     *                                         per option (false, default)
1576
     *
1577
     * @return string One line of the csv file
1578
     *
1579
     * @author Patrick Cool <[email protected]>, Ghent University
1580
     *
1581
     * @version February 2007
1582
     */
1583
    public static function export_complete_report_row(
1584
        CSurvey $survey,
1585
        $possible_options,
1586
        $answers_of_user,
1587
        $user,
1588
        $display_extra_user_fields = false,
1589
        $compact = false
1590
    ) {
1591
        $return = '';
1592
        if (0 == $survey->getAnonymous()) {
1593
            if (0 !== intval($user)) {
1594
                $userInfo = api_get_user_info($user);
1595
                if (!empty($userInfo)) {
1596
                    $user_displayed = $userInfo['complete_name_with_username'];
1597
                } else {
1598
                    $user_displayed = '-';
1599
                }
1600
                $return .= $user_displayed.';';
1601
            } else {
1602
                $return .= $user.';';
1603
            }
1604
        } else {
1605
            $return .= '-;'; // The user column
1606
        }
1607
1608
        if ($display_extra_user_fields) {
1609
            // Show user fields data, if any, for this user
1610
            $user_fields_values = UserManager::get_extra_user_data(
1611
                $user,
1612
                false,
1613
                false,
1614
                false,
1615
                true
1616
            );
1617
            foreach ($user_fields_values as &$value) {
1618
                $return .= '"'.str_replace('"', '""', api_html_entity_decode(strip_tags($value), ENT_QUOTES)).'";';
1619
            }
1620
        }
1621
1622
        if (is_array($possible_options)) {
1623
            foreach ($possible_options as $question_id => $possible_option) {
1624
                if (is_array($possible_option) && count($possible_option) > 0) {
1625
                    foreach ($possible_option as $option_id => &$value) {
1626
                        // For each option of this question, look if it matches the user's answer
1627
                        $my_answer_of_user = !isset($answers_of_user[$question_id]) || isset($answers_of_user[$question_id]) && null == $answers_of_user[$question_id] ? [] : $answers_of_user[$question_id];
1628
                        $key = array_keys($my_answer_of_user);
1629
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
1630
                            // If this is an open type question (type starts by 'open'), take whatever answer is given
1631
                            $return .= '"'.
1632
                                str_replace(
1633
                                    '"',
1634
                                    '""',
1635
                                    api_html_entity_decode(
1636
                                        strip_tags(
1637
                                            $answers_of_user[$question_id][$key[0]]['option_id']
1638
                                        ),
1639
                                        ENT_QUOTES
1640
                                    )
1641
                                ).
1642
                                '";';
1643
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1644
                            //$return .= 'v';
1645
                            if ($compact) {
1646
                                // If we asked for a compact view, show only one column for the question
1647
                                // and fill it with the text of the selected option (i.e. "Yes") instead of an ID
1648
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1649
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1650
                                } else {
1651
                                    $return .= '"'.
1652
                                        str_replace(
1653
                                            '"',
1654
                                            '""',
1655
                                            api_html_entity_decode(
1656
                                                strip_tags(
1657
                                                    $possible_option[$option_id]
1658
                                                ),
1659
                                                ENT_QUOTES
1660
                                            )
1661
                                        ).
1662
                                        '";';
1663
                                }
1664
                            } else {
1665
                                // If we don't want a compact view, show one column per possible option and mark a 'v'
1666
                                // or the defined value in the corresponding column if the user selected it
1667
                                if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1668
                                    $return .= $answers_of_user[$question_id][$option_id]['value'].";";
1669
                                } else {
1670
                                    $return .= 'v;';
1671
                                }
1672
                            }
1673
                        } else {
1674
                            if (!$compact) {
1675
                                $return .= ';';
1676
                            }
1677
                        }
1678
                    }
1679
                }
1680
            }
1681
        }
1682
        $return .= "\n";
1683
1684
        return $return;
1685
    }
1686
1687
    public static function export_complete_report_xls(CSurvey $survey, $filename, $user_id = 0, $returnFile = false)
1688
    {
1689
        $course_id = api_get_course_int_id();
1690
        $user_id = (int) $user_id;
1691
        $surveyId = $survey->getIid();
1692
1693
        if (empty($course_id) || empty($surveyId)) {
1694
            return false;
1695
        }
1696
1697
        // Show extra fields blank space (enough for extra fields on next line)
1698
        // Show user fields section with a big th colspan that spans over all fields
1699
        $extra_user_fields = UserManager::get_extra_fields(
1700
            0,
1701
            0,
1702
            5,
1703
            'ASC',
1704
            false,
1705
            true
1706
        );
1707
        $list = [];
1708
        $num = count($extra_user_fields);
1709
        for ($i = 0; $i < $num; $i++) {
1710
            $list[0][] = '';
1711
        }
1712
1713
        $display_extra_user_fields = true;
1714
1715
        // Database table definitions
1716
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1717
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1718
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1719
1720
        // First line (questions)
1721
        $sql = "SELECT
1722
                    questions.question_id,
1723
                    questions.type,
1724
                    questions.survey_question,
1725
                    count(options.iid) as number_of_options
1726
				FROM $table_survey_question questions
1727
				LEFT JOIN $table_survey_question_option options
1728
                ON
1729
                  questions.iid = options.question_id
1730
				WHERE
1731
				    survey_question NOT LIKE '%{{%' AND
1732
				    questions.type <> 'pagebreak' AND
1733
				    questions.survey_id = $surveyId
1734
				GROUP BY questions.question_id
1735
				ORDER BY questions.sort ASC";
1736
        $result = Database::query($sql);
1737
        $line = 1;
1738
        $column = 1;
1739
        while ($row = Database::fetch_array($result)) {
1740
            // We show the questions if
1741
            // 1. there is no question filter and the export button has not been clicked
1742
            // 2. there is a quesiton filter but the question is selected for display
1743
            if (!(isset($_POST['submit_question_filter'])) ||
1744
                (isset($_POST['submit_question_filter']) && is_array($_POST['questions_filter']) &&
1745
                in_array($row['question_id'], $_POST['questions_filter']))
1746
            ) {
1747
                // We do not show comment and pagebreak question types
1748
                if ('pagebreak' !== $row['type']) {
1749
                    if (0 == $row['number_of_options'] && ('open' === $row['type'] || 'comment' === $row['type'])) {
1750
                        $list[$line][$column] = api_html_entity_decode(
1751
                            strip_tags($row['survey_question']),
1752
                            ENT_QUOTES
1753
                        );
1754
                        $column++;
1755
                    } else {
1756
                        for ($ii = 0; $ii < $row['number_of_options']; $ii++) {
1757
                            $list[$line][$column] = api_html_entity_decode(
1758
                                strip_tags($row['survey_question']),
1759
                                ENT_QUOTES
1760
                            );
1761
                            $column++;
1762
                        }
1763
                    }
1764
                }
1765
            }
1766
        }
1767
1768
        $line++;
1769
        $column = 1;
1770
        // Show extra field values
1771
        if ($display_extra_user_fields) {
1772
            // Show the fields names for user fields
1773
            foreach ($extra_user_fields as &$field) {
1774
                $list[$line][$column] = api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES);
1775
                $column++;
1776
            }
1777
        }
1778
1779
        // Getting all the questions and options (second line)
1780
        $sql = "SELECT
1781
                    survey_question.iid question_id,
1782
                    survey_question.survey_id,
1783
                    survey_question.survey_question,
1784
                    survey_question.display,
1785
                    survey_question.sort,
1786
                    survey_question.type,
1787
                    survey_question_option.iid question_option_id,
1788
                    survey_question_option.option_text,
1789
                    survey_question_option.sort as option_sort
1790
				FROM $table_survey_question survey_question
1791
				LEFT JOIN $table_survey_question_option survey_question_option
1792
				ON
1793
				    survey_question.iid = survey_question_option.question_id
1794
				WHERE
1795
				    survey_question NOT LIKE '%{{%' AND
1796
				    survey_question.type <> 'pagebreak' AND
1797
				    survey_question.survey_id = $surveyId
1798
				ORDER BY survey_question.sort ASC, survey_question_option.sort ASC";
1799
        $result = Database::query($sql);
1800
        $possible_answers = [];
1801
        $possible_answers_type = [];
1802
        while ($row = Database::fetch_array($result)) {
1803
            // We show the options if
1804
            // 1. there is no question filter and the export button has not been clicked
1805
            // 2. there is a quesiton filter but the question is selected for display
1806
            if (!isset($_POST['submit_question_filter']) ||
1807
                (isset($_POST['questions_filter']) && is_array($_POST['questions_filter']) &&
1808
                in_array($row['question_id'], $_POST['questions_filter']))
1809
            ) {
1810
                // We do not show comment and pagebreak question types
1811
                if ('pagebreak' !== $row['type']) {
1812
                    $list[$line][$column] = api_html_entity_decode(
1813
                        strip_tags($row['option_text']),
1814
                        ENT_QUOTES
1815
                    );
1816
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1817
                    $possible_answers_type[$row['question_id']] = $row['type'];
1818
                    $column++;
1819
                }
1820
            }
1821
        }
1822
1823
        // Getting all the answers of the users
1824
        $line++;
1825
        $column = 0;
1826
        $old_user = '';
1827
        $answers_of_user = [];
1828
        $sql = "SELECT * FROM $table_survey_answer
1829
                WHERE c_id = $course_id AND survey_id = $surveyId";
1830
        if (0 != $user_id) {
1831
            $sql .= " AND user='".$user_id."' ";
1832
        }
1833
        $sql .= ' ORDER BY user ASC';
1834
1835
        $open_question_iterator = 1;
1836
        $result = Database::query($sql);
1837
        while ($row = Database::fetch_array($result)) {
1838
            if ($old_user != $row['user'] && '' != $old_user) {
1839
                $return = self::export_complete_report_row_xls(
1840
                    $survey,
1841
                    $possible_answers,
1842
                    $answers_of_user,
1843
                    $old_user,
1844
                    true
1845
                );
1846
                foreach ($return as $elem) {
1847
                    $list[$line][$column] = $elem;
1848
                    $column++;
1849
                }
1850
                $answers_of_user = [];
1851
                $line++;
1852
                $column = 0;
1853
            }
1854
            if ('open' === $possible_answers_type[$row['question_id']] || 'comment' === $possible_answers_type[$row['question_id']]) {
1855
                $temp_id = 'open'.$open_question_iterator;
1856
                $answers_of_user[$row['question_id']][$temp_id] = $row;
1857
                $open_question_iterator++;
1858
            } else {
1859
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1860
            }
1861
            $old_user = $row['user'];
1862
        }
1863
1864
        $return = self::export_complete_report_row_xls(
1865
            $survey,
1866
            $possible_answers,
1867
            $answers_of_user,
1868
            $old_user,
1869
            true
1870
        );
1871
1872
        // this is to display the last user
1873
        if (!empty($return)) {
1874
            foreach ($return as $elem) {
1875
                $list[$line][$column] = $elem;
1876
                $column++;
1877
            }
1878
        }
1879
1880
        Export::arrayToXls($list, $filename);
1881
1882
        return null;
1883
    }
1884
1885
    /**
1886
     * Add a line to the csv file.
1887
     *
1888
     * @param array Possible answers
1889
     * @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...
1890
     * @param mixed User ID or user details as string - Used as a string in the result string
1891
     * @param bool Whether to display user fields or not
1892
     *
1893
     * @return array
1894
     */
1895
    public static function export_complete_report_row_xls(
1896
        CSurvey $survey,
1897
        $possible_options,
1898
        $answers_of_user,
1899
        $user,
1900
        $display_extra_user_fields = false
1901
    ) {
1902
        $return = [];
1903
        if (0 == $survey->getAnonymous()) {
1904
            if (0 !== (int) $user) {
1905
                $userInfo = api_get_user_info($user);
1906
                if ($userInfo) {
1907
                    $user_displayed = $userInfo['complete_name_with_username'];
1908
                } else {
1909
                    $user_displayed = '-';
1910
                }
1911
                $return[] = $user_displayed;
1912
            } else {
1913
                $return[] = $user;
1914
            }
1915
        } else {
1916
            $return[] = '-'; // The user column
1917
        }
1918
1919
        if ($display_extra_user_fields) {
1920
            //show user fields data, if any, for this user
1921
            $user_fields_values = UserManager::get_extra_user_data(
1922
                $user,
1923
                false,
1924
                false,
1925
                false,
1926
                true
1927
            );
1928
            foreach ($user_fields_values as $value) {
1929
                $return[] = api_html_entity_decode(strip_tags($value), ENT_QUOTES);
1930
            }
1931
        }
1932
1933
        if (is_array($possible_options)) {
1934
            foreach ($possible_options as $question_id => &$possible_option) {
1935
                if (is_array($possible_option) && count($possible_option) > 0) {
1936
                    foreach ($possible_option as $option_id => &$value) {
1937
                        $my_answers_of_user = $answers_of_user[$question_id] ?? [];
1938
                        $key = array_keys($my_answers_of_user);
1939
                        if (isset($key[0]) && 'open' === substr($key[0], 0, 4)) {
1940
                            $return[] = api_html_entity_decode(
1941
                                strip_tags($answers_of_user[$question_id][$key[0]]['option_id']),
1942
                                ENT_QUOTES
1943
                            );
1944
                        } elseif (!empty($answers_of_user[$question_id][$option_id])) {
1945
                            if (0 != $answers_of_user[$question_id][$option_id]['value']) {
1946
                                $return[] = $answers_of_user[$question_id][$option_id]['value'];
1947
                            } else {
1948
                                $return[] = 'v';
1949
                            }
1950
                        } else {
1951
                            $return[] = '';
1952
                        }
1953
                    }
1954
                }
1955
            }
1956
        }
1957
1958
        return $return;
1959
    }
1960
1961
    /**
1962
     * This function displays the comparative report which
1963
     * allows you to compare two questions
1964
     * A comparative report creates a table where one question
1965
     * is on the x axis and a second question is on the y axis.
1966
     * In the intersection is the number of people who have
1967
     * answered positive on both options.
1968
     *
1969
     * @return string HTML code
1970
     *
1971
     * @author Patrick Cool <[email protected]>, Ghent University
1972
     *
1973
     * @version February 2007
1974
     */
1975
    public static function display_comparative_report()
1976
    {
1977
        // Allowed question types for comparative report
1978
        $allowed_question_types = [
1979
            'yesno',
1980
            'multiplechoice',
1981
            'multipleresponse',
1982
            'dropdown',
1983
            'percentage',
1984
            'score',
1985
        ];
1986
1987
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
1988
1989
        // Getting all the questions
1990
        $questions = SurveyManager::get_questions($surveyId);
0 ignored issues
show
Deprecated Code introduced by
The function SurveyManager::get_questions() 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

1990
        $questions = /** @scrutinizer ignore-deprecated */ SurveyManager::get_questions($surveyId);
Loading history...
1991
1992
        // Actions bar
1993
        echo '<div class="actions">';
1994
        echo '<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq()
1995
            .'">'
1996
            .Display::return_icon(
1997
                'back.png',
1998
                get_lang('Back to').' '.get_lang('Reporting overview'),
1999
                [],
2000
                ICON_SIZE_MEDIUM
2001
            )
2002
            .'</a>';
2003
        echo '</div>';
2004
2005
        // Displaying an information message that only the questions with predefined answers can be used in a comparative report
2006
        echo Display::return_message(get_lang('Only questions with predefined answers can be used'), 'normal', false);
2007
2008
        $xAxis = isset($_GET['xaxis']) ? Security::remove_XSS($_GET['xaxis']) : '';
2009
        $yAxis = isset($_GET['yaxis']) ? Security::remove_XSS($_GET['yaxis']) : '';
2010
2011
        $url = api_get_self().'?'.api_get_cidreq().'&action='.Security::remove_XSS($_GET['action'])
2012
            .'&survey_id='.$surveyId.'&xaxis='.$xAxis.'&y='.$yAxis;
2013
2014
        $form = new FormValidator('compare', 'get', $url);
2015
        $form->addHidden('action', Security::remove_XSS($_GET['action']));
2016
        $form->addHidden('survey_id', $surveyId);
2017
        $optionsX = ['----'];
2018
        $optionsY = ['----'];
2019
        $defaults = [];
2020
        foreach ($questions as $key => &$question) {
2021
            // Ignored tagged questions
2022
            if ($question) {
2023
                if (false !== strpos($question['question'], '{{')) {
2024
                    $question = null;
2025
                    continue;
2026
                }
2027
            }
2028
            if (is_array($allowed_question_types)) {
2029
                if (in_array($question['type'], $allowed_question_types)) {
2030
                    if (isset($_GET['xaxis']) && $_GET['xaxis'] == $question['question_id']) {
2031
                        $defaults['xaxis'] = $question['question_id'];
2032
                    }
2033
2034
                    if (isset($_GET['yaxis']) && $_GET['yaxis'] == $question['question_id']) {
2035
                        $defaults['yaxis'] = $question['question_id'];
2036
                    }
2037
2038
                    $optionsX[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2039
                    $optionsY[$question['question_id']] = api_substr(strip_tags($question['question']), 0, 90);
2040
                }
2041
            }
2042
        }
2043
2044
        $form->addSelect('xaxis', get_lang('Select the question on the X axis'), $optionsX);
2045
        $form->addSelect('yaxis', get_lang('Select the question on the Y axis'), $optionsY);
2046
2047
        $form->addButtonSearch(get_lang('Compare questions'));
2048
        $form->setDefaults($defaults);
2049
        $form->display();
2050
2051
        // Getting all the information of the x axis
2052
        if (is_numeric($xAxis)) {
2053
            $question_x = SurveyManager::get_question($xAxis);
2054
        }
2055
2056
        // Getting all the information of the y axis
2057
        if (is_numeric($yAxis)) {
2058
            $question_y = SurveyManager::get_question($yAxis);
2059
        }
2060
2061
        if (is_numeric($xAxis) && is_numeric($yAxis) && $question_x && $question_y) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_x does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $question_y does not seem to be defined for all execution paths leading up to this point.
Loading history...
2062
            // Getting the answers of the two questions
2063
            $answers_x = self::get_answers_of_question_by_user($surveyId, $xAxis);
2064
            $answers_y = self::get_answers_of_question_by_user($surveyId, $yAxis);
2065
2066
            // Displaying the table
2067
            $tableHtml = '<table border="1" class="table table-hover table-striped data_table">';
2068
            $xOptions = [];
2069
            // The header
2070
            $tableHtml .= '<tr>';
2071
            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...
2072
                if (0 == $ii) {
2073
                    $tableHtml .= '<th>&nbsp;</th>';
2074
                } else {
2075
                    if ('score' == $question_x['type']) {
2076
                        for ($x = 1; $x <= $question_x['maximum_score']; $x++) {
2077
                            $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'<br />'.$x.'</th>';
2078
                        }
2079
                        $x = '';
2080
                    } else {
2081
                        $tableHtml .= '<th>'.$question_x['answers'][($ii - 1)].'</th>';
2082
                    }
2083
                    $optionText = strip_tags($question_x['answers'][$ii - 1]);
2084
                    $optionText = html_entity_decode($optionText);
2085
                    array_push($xOptions, trim($optionText));
2086
                }
2087
            }
2088
            $tableHtml .= '</tr>';
2089
            $chartData = [];
2090
            // The main part
2091
            for ($ij = 0; $ij < count($question_y['answers']); $ij++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

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

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

2567
                $full_invitation_text = /** @scrutinizer ignore-type */ $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
Loading history...
2568
            }
2569
        }
2570
2571
        // Sending the mail
2572
        $sender_name = api_get_person_name($_user['firstName'], $_user['lastName'], null, PERSON_NAME_EMAIL_ADDRESS);
2573
        $sender_email = $_user['mail'];
2574
        $sender_user_id = api_get_user_id();
2575
2576
        $replyto = [];
2577
        if ('noreply' === api_get_setting('survey_email_sender_noreply')) {
2578
            $noreply = api_get_setting('noreply_email_address');
2579
            if (!empty($noreply)) {
2580
                $replyto['Reply-to'] = $noreply;
2581
                $sender_name = $noreply;
2582
                $sender_email = $noreply;
2583
                $sender_user_id = null;
2584
            }
2585
        }
2586
2587
        // Optionally: finding the e-mail of the course user
2588
        if (is_numeric($invitedUser)) {
2589
            MessageManager::send_message(
2590
                $invitedUser,
2591
                $invitation_title,
2592
                $full_invitation_text,
2593
                [],
2594
                [],
2595
                null,
2596
                null,
2597
                null,
2598
                null,
2599
                $sender_user_id,
2600
                true
2601
            );
2602
        } else {
2603
            @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

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