Passed
Pull Request — master (#5766)
by
unknown
07:08
created

SurveyUtil::export_complete_report_row_xls()   C

Complexity

Conditions 15
Paths 16

Size

Total Lines 64
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 40
nc 16
nop 5
dl 0
loc 64
rs 5.9166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AbstractResource;
6
use Chamilo\CoreBundle\Entity\Course;
7
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
8
use Chamilo\CoreBundle\Entity\User;
9
use Chamilo\CoreBundle\Framework\Container;
10
use Chamilo\CourseBundle\Entity\CGroup;
11
use Chamilo\CourseBundle\Entity\CSurvey;
12
use Chamilo\CourseBundle\Entity\CSurveyAnswer;
13
use Chamilo\CourseBundle\Entity\CSurveyInvitation;
14
use Chamilo\CourseBundle\Entity\CSurveyQuestion;
15
use Chamilo\CourseBundle\Entity\CSurveyQuestionOption;
16
use ChamiloSession as Session;
17
use Chamilo\CoreBundle\Component\Utils\ActionIcon;
18
use Chamilo\CoreBundle\Component\Utils\ToolIcon;
19
use Chamilo\CoreBundle\Component\Utils\ObjectIcon;
20
use Chamilo\CoreBundle\Component\Utils\StateIcon;
21
22
/**
23
 * This class offers a series of general utility functions for survey querying and display.
24
 */
25
class SurveyUtil
26
{
27
    /**
28
     * Checks whether the given survey has a pagebreak question as the first
29
     * or the last question.
30
     * If so, break the current process, displaying an error message.
31
     *
32
     * @param int  $survey_id Survey ID (database ID)
33
     * @param bool $continue  Optional. Whether to continue the current
34
     *                        process or exit when breaking condition found. Defaults to true (do not break).
35
     */
36
    public static function check_first_last_question($survey_id, $continue = true)
37
    {
38
        // Table definitions
39
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
40
        $course_id = api_get_course_int_id();
41
        $survey_id = (int) $survey_id;
42
43
        // Getting the information of the question
44
        $sql = "SELECT * FROM $tbl_survey_question
45
                WHERE survey_id='".$survey_id."'
46
                ORDER BY sort ASC";
47
        $result = Database::query($sql);
48
        $total = Database::num_rows($result);
49
        $counter = 1;
50
        $error = false;
51
        while ($row = Database::fetch_assoc($result)) {
52
            if (1 == $counter && 'pagebreak' === $row['type']) {
53
                echo Display::return_message(get_lang('The page break cannot be the first'), 'error', false);
54
                $error = true;
55
            }
56
            if ($counter == $total && 'pagebreak' === $row['type']) {
57
                echo Display::return_message(get_lang('The page break cannot be the last one'), 'error', false);
58
                $error = true;
59
            }
60
            $counter++;
61
        }
62
63
        if (!$continue && $error) {
64
            Display::display_footer();
65
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
66
        }
67
    }
68
69
    /**
70
     * This function removes an (or multiple) answer(s) of a user on a question of a survey.
71
     *
72
     * @param mixed   The user id or email of the person who fills the survey
73
     * @param int The survey id
74
     * @param int The question id
75
     * @param int The option id
76
     *
77
     * @author Patrick Cool <[email protected]>, Ghent University
78
     *
79
     * @version January 2007
80
     */
81
    public static function remove_answer($user, $survey_id, $question_id, $course_id, $lpItemId = 0): void
82
    {
83
        $sessionId = api_get_session_id();
84
        $course_id = intval($course_id);
85
        // table definition
86
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
87
88
        $lpItemCondition = '';
89
        if (!empty($lpItemId)) {
90
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
91
        }
92
        $sessionCondition = '';
93
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
94
            $sessionCondition = api_get_session_condition($sessionId);
95
        }
96
97
        $sql = "DELETE FROM $table
98
				WHERE
99
                    user = '".Database::escape_string($user)."' AND
100
                    survey_id = '".intval($survey_id)."' AND
101
                    question_id = '".intval($question_id)."'
102
                    $sessionCondition
103
                    $lpItemCondition";
104
        Database::query($sql);
105
    }
106
107
    public static function saveAnswer(
108
        $user,
109
        CSurvey $survey,
110
        CSurveyQuestion $question,
111
        $optionId,
112
        $optionValue,
113
        $otherOption = '',
114
        $lpItemId = 0
115
    ): bool {
116
117
        // Make the survey anonymous
118
        if (1 == $survey->getAnonymous()) {
119
            $surveyUser = Session::read('surveyuser');
120
            if (empty($surveyUser)) {
121
                $user = md5($user.time());
122
                Session::write('surveyuser', $user);
123
            } else {
124
                $user = Session::read('surveyuser');
125
            }
126
        }
127
128
        if (!empty($otherOption)) {
129
            $optionId = $optionId.'@:@'.$otherOption;
130
        }
131
132
        $sessionId = api_get_session_id();
133
        $answer = new CSurveyAnswer();
134
        $answer
135
            ->setUser($user)
136
            ->setSurvey($survey)
137
            ->setQuestion($question)
138
            ->setOptionId($optionId)
139
            ->setValue((int) $optionValue)
140
            ->setLpItemId((int) $lpItemId)
141
            ->setSessionId($sessionId ?: null)
142
        ;
143
144
        $em = Database::getManager();
145
        $em->persist($answer);
146
        $em->flush();
147
148
        $insertId = $answer->getIid();
149
        if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
150
            return true;
151
        }
152
153
        return false;
154
    }
155
156
    /**
157
     * This function checks the parameters that are used in this page.
158
     *
159
     * @return string $people_filled The header, an error and the footer if any parameter fails, else it returns true
160
     *
161
     * @author Patrick Cool <[email protected]>, Ghent University
162
     *
163
     * @version February 2007
164
     */
165
    public static function check_parameters($people_filled)
166
    {
167
        $error = false;
168
169
        // Getting the survey data
170
        $survey_data = SurveyManager::get_survey($_GET['survey_id']);
171
172
        // $_GET['survey_id'] has to be numeric
173
        if (!is_numeric($_GET['survey_id'])) {
174
            $error = get_lang('Unknown survey id');
175
        }
176
177
        // $_GET['action']
178
        $allowed_actions = [
179
            'overview',
180
            'questionreport',
181
            'userreport',
182
            'comparativereport',
183
            'completereport',
184
            'deleteuserreport',
185
        ];
186
        if (isset($_GET['action']) && !in_array($_GET['action'], $allowed_actions)) {
187
            $error = get_lang('Action not allowed');
188
        }
189
190
        // User report
191
        if (isset($_GET['action']) && 'userreport' == $_GET['action']) {
192
            if (0 == $survey_data['anonymous']) {
193
                foreach ($people_filled as $key => &$value) {
194
                    $people_filled_userids[] = $value['invited_user'];
195
                }
196
            } else {
197
                $people_filled_userids = $people_filled;
198
            }
199
200
            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...
201
                $error = get_lang('Unknow user');
202
            }
203
        }
204
205
        // Question report
206
        if (isset($_GET['action']) && 'questionreport' == $_GET['action']) {
207
            if (isset($_GET['question']) && !is_numeric($_GET['question'])) {
208
                $error = get_lang('Unknown question');
209
            }
210
        }
211
212
        if ($error) {
213
            $tool_name = get_lang('Reporting');
214
            Display::addFlash(
215
                Display::return_message(
216
                    get_lang('Error').': '.$error,
217
                    'error',
218
                    false
219
                )
220
            );
221
            Display::display_header($tool_name);
222
            Display::display_footer();
223
            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...
224
        }
225
226
        return true;
227
    }
228
229
    public static function handleReportingActions(CSurvey $survey, array $people_filled = [])
230
    {
231
        $action = $_GET['action'] ?? '';
232
233
        switch ($action) {
234
            case 'questionreport':
235
                self::display_question_report($survey);
236
                break;
237
            case 'userreport':
238
                self::displayUserReport($survey, $people_filled);
239
                break;
240
            case 'comparativereport':
241
                self::display_comparative_report();
242
                break;
243
            case 'completereport':
244
                if (true === api_get_configuration_value('allow_survey_tool_in_lp')) {
245
                    $surveysAnswered = SurveyManager::getInvitationsAnswered($survey->getCode(), api_get_course_int_id(), api_get_session_id());
246
                    if (count($surveysAnswered) > 0) {
247
                        foreach ($surveysAnswered as $survey) {
248
                            echo self::displayCompleteReport($survey, 0, true, true, !$survey->getAnonymous(), $survey->getLpItemId());
249
                        }
250
                    }
251
                } else {
252
                    echo self::displayCompleteReport($survey, 0, true, true, !$survey->getAnonymous());
253
                }
254
                break;
255
            case 'deleteuserreport':
256
                self::delete_user_report($survey->getIid(), $_GET['user']);
257
                break;
258
        }
259
    }
260
261
    /**
262
     * This function deletes the report of an user who wants to retake the survey.
263
     *
264
     * @param int $survey_id
265
     * @param int $user_id
266
     *
267
     * @author Christian Fasanando Flores <[email protected]>
268
     *
269
     * @version November 2008
270
     */
271
    public static function delete_user_report($survey_id, $user_id)
272
    {
273
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
274
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
275
        $table_survey = Database::get_course_table(TABLE_SURVEY);
276
277
        $course_id = api_get_course_int_id();
278
        $survey_id = (int) $survey_id;
279
        $user_id = Database::escape_string($user_id);
280
281
        if (!empty($survey_id) && !empty($user_id)) {
282
283
            $sessionCondition = '';
284
            if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
285
                $sessionId = api_get_session_id();
286
                $sessionCondition = api_get_session_condition($sessionId);
287
            }
288
289
            // delete data from survey_answer by user_id and survey_id
290
            $sql = "DELETE FROM $table_survey_answer
291
			        WHERE c_id = $course_id AND survey_id = '".$survey_id."' AND user = '".$user_id."' $sessionCondition";
292
            Database::query($sql);
293
            // update field answered from survey_invitation by user_id and survey_id
294
            $sql = "UPDATE $table_survey_invitation SET answered = '0'
295
			        WHERE
296
			            c_id = $course_id AND
297
			            survey_id = (
298
                            SELECT iid FROM $table_survey
299
                            WHERE
300
                                iid = '".$survey_id."'
301
                        ) AND
302
			            user_id = '".$user_id."'  $sessionCondition";
303
            $result = Database::query($sql);
304
        }
305
306
        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...
307
            $message = get_lang('The user\'s answers to the survey have been succesfully removed.').'<br />
308
					<a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action=userreport&survey_id='
309
                .$survey_id.'">'.
310
                get_lang('Go back').'</a>';
311
            echo Display::return_message($message, 'confirmation', false);
312
        }
313
    }
314
315
    /**
316
     * @return string
317
     */
318
    public static function displayUserReportForm(CSurvey $survey, array $people_filled = [])
319
    {
320
        $surveyId = $survey->getIid();
321
        // Step 1: selection of the user
322
        echo "<script>
323
        function jumpMenu(targ,selObj,restore) {
324
            eval(targ+\".location='\"+selObj.options[selObj.selectedIndex].value+\"'\");
325
            if (restore) selObj.selectedIndex=0;
326
        }
327
		</script>";
328
        echo get_lang('Select user who filled the survey').'<br />';
329
        echo '<select name="user" onchange="jumpMenu(\'parent\',this,0)">';
330
        echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
331
            .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($_GET['action']) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

331
            ./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">'
Loading history...
332
            .get_lang('User').'</option>';
333
334
        foreach ($people_filled as $key => &$person) {
335
            if (0 == $survey->getAnonymous()) {
336
                $name = $person['user_info']['complete_name_with_username'];
337
                $id = $person['user_id'];
338
                if ('' == $id) {
339
                    $id = $person['invited_user'];
340
                    $name = $person['invited_user'];
341
                }
342
            } else {
343
                $name = get_lang('Anonymous').' '.($key + 1);
344
                $id = $person;
345
            }
346
            echo '<option value="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='
347
                .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&user='
348
                .Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($id) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

348
                ./** @scrutinizer ignore-type */ Security::remove_XSS($id).'&'.api_get_cidreq().'" ';
Loading history...
349
            if (isset($_GET['user']) && $_GET['user'] == $id) {
350
                echo 'selected="selected"';
351
            }
352
            echo '>'.$name.'</option>';
353
        }
354
        echo '</select>';
355
    }
356
357
    /**
358
     * @param int   $userId
359
     * @param array $survey_data
360
     * @param bool  $addMessage
361
     */
362
    public static function displayUserReportAnswers($userId, CSurvey $survey, $addMessage = true)
363
    {
364
        // Database table definitions
365
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
366
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
367
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
368
        $course_id = api_get_course_int_id();
369
        $surveyId = $survey->getIid();
370
        $userId = Database::escape_string($userId);
371
372
        $content = '';
373
        // Step 2: displaying the survey and the answer of the selected users
374
        if (!empty($userId)) {
375
            if ($addMessage) {
376
                $content .= Display::return_message(
377
                    get_lang('This screen displays an exact copy of the form as it was filled by the user'),
378
                    'normal',
379
                    false
380
                );
381
            }
382
383
            // Getting all the questions and options
384
            $sql = "SELECT
385
			            survey_question.iid question_id,
386
			            survey_question.survey_id,
387
			            survey_question.survey_question,
388
			            survey_question.display,
389
			            survey_question.max_value,
390
			            survey_question.sort,
391
			            survey_question.type,
392
                        survey_question_option.iid question_option_id,
393
                        survey_question_option.option_text,
394
                        survey_question_option.sort as option_sort
395
					FROM $table_survey_question survey_question
396
					LEFT JOIN $table_survey_question_option survey_question_option
397
					ON
398
					    survey_question.iid = survey_question_option.question_id
399
					WHERE
400
					    survey_question NOT LIKE '%{{%' AND
401
					    survey_question.survey_id = '".$surveyId."'
402
					ORDER BY survey_question.sort, survey_question_option.sort ASC";
403
            $result = Database::query($sql);
404
            while ($row = Database::fetch_assoc($result)) {
405
                if ('pagebreak' !== $row['type']) {
406
                    $questions[$row['sort']]['question_id'] = $row['question_id'];
407
                    $questions[$row['sort']]['survey_id'] = $row['survey_id'];
408
                    $questions[$row['sort']]['survey_question'] = $row['survey_question'];
409
                    $questions[$row['sort']]['display'] = $row['display'];
410
                    $questions[$row['sort']]['type'] = $row['type'];
411
                    $questions[$row['sort']]['maximum_score'] = $row['max_value'];
412
                    $questions[$row['sort']]['options'][$row['question_option_id']] = $row['option_text'];
413
                }
414
            }
415
416
            $sessionCondition = '';
417
            if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
418
                $sessionId = api_get_session_id();
419
                $sessionCondition = api_get_session_condition($sessionId);
420
            }
421
422
            // Getting all the answers of the user
423
            $sql = "SELECT * FROM $table_survey_answer
424
			        WHERE
425
                        survey_id = '".$surveyId."' AND
426
                        user = '".$userId."' $sessionCondition";
427
            $result = Database::query($sql);
428
            while ($row = Database::fetch_assoc($result)) {
429
                $answers[$row['question_id']][] = $row['option_id'];
430
                $all_answers[$row['question_id']][] = $row;
431
            }
432
433
            // Displaying all the questions
434
            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...
435
                // If the question type is a scoring then we have to format the answers differently
436
                switch ($question['type']) {
437
                    case 'score':
438
                        $finalAnswer = [];
439
                        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...
440
                            foreach ($all_answers[$question['question_id']] as $key => &$answer_array) {
441
                                $finalAnswer[$answer_array['option_id']] = $answer_array['value'];
442
                            }
443
                        }
444
                        break;
445
                    case 'multipleresponse':
446
                        $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...
447
                        break;
448
                    default:
449
                        $finalAnswer = '';
450
                        if (isset($all_answers[$question['question_id']])) {
451
                            $finalAnswer = $all_answers[$question['question_id']][0]['option_id'];
452
                        }
453
                        break;
454
                }
455
456
                $display = survey_question::createQuestion($question['type']);
457
                $url = api_get_self();
458
                $form = new FormValidator('question', 'post', $url);
459
                $form->addHtml('<div class="survey_question_wrapper"><div class="survey_question">');
460
                $form->addHtml($question['survey_question']);
461
                $display->render($form, $question, $finalAnswer);
462
                $form->addHtml('</div></div>');
463
                $content .= $form->returnForm();
464
            }
465
        }
466
467
        return $content;
468
    }
469
470
    /**
471
     * This function displays the user report which is basically nothing more
472
     * than a one-page display of all the questions
473
     * of the survey that is filled with the answers of the person who filled the survey.
474
     *
475
     * @return string html code of the one-page survey with the answers of the selected user
476
     *
477
     * @author Patrick Cool <[email protected]>, Ghent University
478
     *
479
     * @version February 2007 - Updated March 2008
480
     */
481
    public static function displayUserReport(CSurvey $survey, $people_filled, $addActionBar = true)
482
    {
483
        $surveyId = $survey->getIid();
484
        $reportingUrl = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
485
486
        // Actions bar
487
        if ($addActionBar) {
488
            $actions = '<a href="'.$reportingUrl.'">'.
489
                Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'))
490
                .'</a>';
491
            if (isset($_GET['user'])) {
492
                if (api_is_allowed_to_edit()) {
493
                    // The delete link
494
                    $actions .= '<a
495
                        href="'.$reportingUrl.'&action=deleteuserreport&user='.Security::remove_XSS($_GET['user']).'" >'.
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($_GET['user']) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

495
                        href="'.$reportingUrl.'&action=deleteuserreport&user='./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['user']).'" >'.
Loading history...
496
                        Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Delete')).'</a>';
497
                }
498
499
                // Export the user report
500
                $actions .= '<a href="javascript: void(0);" onclick="document.form1a.submit();">'
501
                    .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a> ';
502
                $actions .= '<a href="javascript: void(0);" onclick="document.form1b.submit();">'
503
                    .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a> ';
504
                $actions .= '<form id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='
505
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($_GET['action']) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

505
                    ./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
Loading history...
506
                    .Security::remove_XSS($_GET['user']).'">';
507
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
508
                $actions .= '<input type="hidden" name="export_format" value="csv">';
509
                $actions .= '</form>';
510
                $actions .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self().'?action='
511
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'&user_id='
512
                    .Security::remove_XSS($_GET['user']).'">';
513
                $actions .= '<input type="hidden" name="export_report" value="export_report">';
514
                $actions .= '<input type="hidden" name="export_format" value="xls">';
515
                $actions .= '</form>';
516
                $actions .= '<form id="form2" name="form2" method="post" action="'.api_get_self().'?action='
517
                    .Security::remove_XSS($_GET['action']).'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
518
            }
519
            echo Display::toolbarAction('survey', [$actions]);
520
        }
521
522
        echo self::displayUserReportForm($survey, $people_filled);
523
        if (isset($_GET['user'])) {
524
            echo self::displayUserReportAnswers($_GET['user'], $survey);
525
        }
526
    }
527
528
    /**
529
     * This function displays the report by question.
530
     *
531
     * It displays a table with all the options of the question and the number of users who have answered positively on
532
     * the option. The number of users who answered positive on a given option is expressed in an absolute number, in a
533
     * percentage of the total and graphically using bars By clicking on the absolute number you get a list with the
534
     * persons who have answered this. You can then click on the name of the person and you will then go to the report
535
     * by user where you see all the answers of that user.
536
     *
537
     * @return string html code that displays the report by question
538
     *
539
     * @todo allow switching between horizontal and vertical.
540
     * @todo multiple response: percentage are probably not OK
541
     * @todo the question and option text have to be shortened and should expand when the user clicks on it.
542
     * @todo the pagebreak and comment question types should not be shown => removed from $survey_data before
543
     *
544
     * @author Patrick Cool <[email protected]>, Ghent University
545
     *
546
     * @version February 2007 - Updated March 2008
547
     */
548
    public static function display_question_report(CSurvey $survey)
549
    {
550
        $singlePage = isset($_GET['single_page']) ? (int) $_GET['single_page'] : 0;
551
        // Determining the offset of the sql statement (the n-th question of the survey)
552
        $offset = !isset($_GET['question']) ? 0 : (int) $_GET['question'];
553
        $currentQuestion = isset($_GET['question']) ? (int) $_GET['question'] : 0;
554
        $surveyId = $survey->getIid();
555
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
556
        $course_id = api_get_course_int_id();
557
558
        $sessionCondition = '';
559
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
560
            $sessionId = api_get_session_id();
561
            $sessionCondition = api_get_session_condition($sessionId);
562
        }
563
564
        // Database table definitions
565
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
566
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
567
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
568
569
        $actions = '<a
570
            href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'.
571
            Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
572
                '',
573
                ICON_SIZE_MEDIUM
574
            ).'</a>';
575
        $actions .= Display::url(
576
            Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportToPdf')),
577
            'javascript: void(0);',
578
            ['onclick' => 'exportToPdf();']
579
        );
580
581
        echo Display::toolbarAction('survey', [$actions]);
582
583
        $fromUntil = sprintf(
584
            get_lang('FromXUntilY'),
585
            api_get_local_time($survey->getAvailFrom()),
586
            api_get_local_time($survey->getAvailTill())
587
        );
588
        $max = 80;
589
        $data = [
590
            get_lang('SurveyTitle') => cut(strip_tags($survey->getTitle()), $max),
591
            get_lang('SurveySubTitle') => cut(strip_tags($survey->getSubtitle()), $max),
592
            get_lang('Dates') => $fromUntil,
593
            get_lang('SurveyIntroduction') => cut(strip_tags($survey->getIntro()), $max),
594
        ];
595
596
        $table = new HTML_Table(['id' => 'pdf_table', 'class' => 'table']);
597
        $row = 0;
598
        foreach ($data as $label => $item) {
599
            $table->setCellContents($row, 0, $label);
600
            $table->setCellContents($row, 1, $item);
601
            $row++;
602
        }
603
604
        $questions = $survey->getQuestions();
605
        $numberOfQuestions = 0;
606
        foreach ($questions as $question) {
607
            if ('pagebreak' !== $question->getType()) {
608
                $numberOfQuestions++;
609
            }
610
        }
611
612
        $newQuestionList = [];
613
        if ($numberOfQuestions > 0) {
614
            $limitStatement = null;
615
            if (!$singlePage) {
616
                echo '<div id="question_report_questionnumbers" class="pagination">';
617
                if (0 != $currentQuestion) {
618
                    echo '<li><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='.$action.'&'
0 ignored issues
show
Bug introduced by
Are you sure $action of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

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

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

938
                echo '<td><a href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?action='./** @scrutinizer ignore-type */ $action
Loading history...
939
                    .'&survey_id='.$surveyId.'&question='.Security::remove_XSS($offset)
0 ignored issues
show
Bug introduced by
Are you sure Security::remove_XSS($offset) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

939
                    .'&survey_id='.$surveyId.'&question='./** @scrutinizer ignore-type */ Security::remove_XSS($offset)
Loading history...
940
                    .'&viewoption='.$optionId.'&value='.$i.'">'.$absolute_number.'</a></td>';
941
942
                $percentage = 0;
943
                $size = 0;
944
                if (!empty($number_of_answers)) {
945
                    $percentage = round($absolute_number / $number_of_answers * 100, 2);
946
                    $size = ($absolute_number / $number_of_answers * 100 * 2);
947
                }
948
                echo '<td>'.$percentage.' %</td>';
949
                echo '<td>';
950
                if ($size > 0) {
951
                    echo '<div
952
                            style="border:1px solid #264269;
953
                            background-color:#aecaf4;
954
                            height:10px; width:'.$size.'px">
955
                            &nbsp;
956
                        </div>';
957
                }
958
                echo '		</td>';
959
                echo '	</tr>';
960
            }
961
        }
962
        // Displaying the table: footer (totals)
963
        echo '	<tr>';
964
        echo '		<td style="border-top:1px solid black"><b>'.get_lang('Total').'</b></td>';
965
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
966
        echo '		<td style="border-top:1px solid black"><b>'.$number_of_answers.'</b></td>';
967
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
968
        echo '		<td style="border-top:1px solid black">&nbsp;</td>';
969
        echo '	</tr>';
970
        echo '</table>';
971
    }
972
973
    /**
974
     * This functions displays the complete reporting.
975
     *
976
     * @param int  $userId
977
     * @param bool $addActionBar
978
     * @param bool $addFilters
979
     * @param bool $addExtraFields
980
     *
981
     * @return string
982
     */
983
    public static function displayCompleteReport(
984
        CSurvey $survey,
985
        $userId = 0,
986
        $addActionBar = true,
987
        $addFilters = true,
988
        $addExtraFields = true,
989
        $lpItemId = 0
990
    ) {
991
        // Database table definitions
992
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
993
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
994
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
995
996
        $surveyId = $survey->getIid();
997
        $course_id = api_get_course_int_id();
998
999
        if (empty($surveyId) || empty($course_id)) {
1000
            return '';
1001
        }
1002
1003
        $sessionCondition = '';
1004
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
1005
            $sessionId = api_get_session_id();
1006
            $sessionCondition = api_get_session_condition($sessionId);
1007
        }
1008
        $lpItemCondition = '';
1009
        if (!empty($lpItemId)) {
1010
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
1011
        }
1012
1013
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : '';
1014
        $content = '';
1015
        if (!empty($lpItemId)) {
1016
            $tableLp = Database::get_course_table(TABLE_LP_MAIN);
1017
            $tableLpItem = Database::get_course_table(TABLE_LP_ITEM);
1018
            $sql = "SELECT l.name,
1019
                    li.title
1020
                    FROM $tableLpItem li
1021
                    INNER JOIN $tableLp l
1022
                    ON l.iid = li.lp_id AND
1023
                       l.c_id = li.c_id
1024
                    WHERE li.c_id = $course_id AND
1025
                          li.iid = $lpItemId";
1026
            $rs = Database::query($sql);
1027
            if (Database::num_rows($rs) > 0) {
1028
                $row = Database::fetch_assoc($rs);
1029
                $lpName = $row['name'];
1030
                $lpItemTitle = $row['title'];
1031
                $content .= '<h3>'.$lpName.' : '.$lpItemTitle.'</h3>';
1032
            }
1033
        }
1034
1035
        if ($addActionBar) {
1036
            $actions = '<a
1037
                href="'.api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq().'">'
1038
                .Display::getMdiIcon(ActionIcon::BACK, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Back to').' '.get_lang('Reporting overview'),
1039
                    [],
1040
                    ICON_SIZE_MEDIUM
1041
                )
1042
                .'</a>';
1043
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1a.submit();">'
1044
                .Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).'</a>';
1045
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1b.submit();">'
1046
                .Display::getMdiIcon(ActionIcon::EXPORT_SPREADSHEET, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Excel export')).'</a>';
1047
            $actions .= '<a class="survey_export_link" href="javascript: void(0);" onclick="document.form1c.submit();">'
1048
                .Display::getMdiIcon(ActionIcon::EXPORT_ARCHIVE, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('ExportAsCompactCSV')).'</a>';
1049
1050
            $content .= Display::toolbarAction('survey', [$actions]);
1051
1052
            // The form
1053
            $content .= '<form
1054
                id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='.$action.'&survey_id='
0 ignored issues
show
Bug introduced by
Are you sure $action of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1054
                id="form1a" name="form1a" method="post" action="'.api_get_self().'?action='./** @scrutinizer ignore-type */ $action.'&survey_id='
Loading history...
1055
                .$surveyId.'&'.api_get_cidreq().'">';
1056
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1057
            $content .= '<input type="hidden" name="export_format" value="csv">';
1058
            $content .= '</form>';
1059
            $content .= '<form id="form1b" name="form1b" method="post" action="'.api_get_self(
1060
                ).'?action='.$action.'&survey_id='
1061
                .$surveyId.'&'.api_get_cidreq().'">';
1062
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1063
            $content .= '<input type="hidden" name="export_format" value="xls">';
1064
            $content .= '</form>';
1065
            $content .= '<form id="form1c" name="form1c" method="post" action="'.api_get_self(
1066
                ).'?action='.$action.'&survey_id='
1067
                .$surveyId.'&'.api_get_cidreq().'">';
1068
            $content .= '<input type="hidden" name="export_report" value="export_report">';
1069
            $content .= '<input type="hidden" name="export_format" value="csv-compact">';
1070
            $content .= '</form>';
1071
        }
1072
1073
        $content .= '<form
1074
            id="form2"
1075
            name="form2"
1076
            method="post"
1077
            action="'.api_get_self().'?action='.$action.'&survey_id='.$surveyId.'&'.api_get_cidreq().'">';
1078
        $content .= '<br /><table class="table table-hover table-striped data_table" border="1">';
1079
        // Getting the number of options per question
1080
        $content .= '<tr>';
1081
        $content .= '<th>';
1082
1083
        if ($addFilters) {
1084
            if ((isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1085
                (isset($_POST['export_report']) && $_POST['export_report'])
1086
            ) {
1087
                $content .= '<button class="cancel"
1088
                                type="submit"
1089
                                name="reset_question_filter" value="'.get_lang('Reset filter').'">'.
1090
                                get_lang('Reset filter').'</button>';
1091
            }
1092
            $content .= '<button
1093
                            class = "save"
1094
                            type="submit" name="submit_question_filter" value="'.get_lang('Filter').'">'.
1095
                            get_lang('Filter').'</button>';
1096
            $content .= '</th>';
1097
        }
1098
1099
        $display_extra_user_fields = false;
1100
        if ($addExtraFields) {
1101
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1102
                    isset($_POST['export_report']) && $_POST['export_report']) ||
1103
                !empty($_POST['fields_filter'])
1104
            ) {
1105
                // Show user fields section with a big th colspan that spans over all fields
1106
                $extra_user_fields = UserManager::get_extra_fields(
1107
                    0,
1108
                    0,
1109
                    5,
1110
                    'ASC',
1111
                    false,
1112
                    true
1113
                );
1114
                $num = count($extra_user_fields);
1115
                if ($num > 0) {
1116
                    $content .= '<th '.($num > 0 ? ' colspan="'.$num.'"' : '').'>';
1117
                    $content .= '<label>';
1118
                    if ($addFilters) {
1119
                        $content .= '<input type="checkbox" name="fields_filter" value="1" checked="checked"/> ';
1120
                    }
1121
                    $content .= get_lang('Profile attributes');
1122
                    $content .= '</label>';
1123
                    $content .= '</th>';
1124
                    $display_extra_user_fields = true;
1125
                }
1126
            }
1127
        }
1128
1129
        $sql = "SELECT
1130
                  q.iid question_id,
1131
                  q.type,
1132
                  q.survey_question,
1133
                  count(o.iid) as number_of_options
1134
				FROM $table_survey_question q
1135
				LEFT JOIN $table_survey_question_option o
1136
				ON q.iid = o.question_id
1137
				WHERE
1138
				    survey_question NOT LIKE '%{{%' AND
1139
				    q.survey_id = '".$surveyId."'
1140
				GROUP BY q.iid
1141
				ORDER BY q.sort ASC";
1142
        $result = Database::query($sql);
1143
        $questions = [];
1144
        while ($row = Database::fetch_array($result)) {
1145
            // We show the questions if
1146
            // 1. there is no question filter and the export button has not been clicked
1147
            // 2. there is a quesiton filter but the question is selected for display
1148
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1149
                (is_array($_POST['questions_filter']) &&
1150
                in_array($row['question_id'], $_POST['questions_filter']))
1151
            ) {
1152
                // We do not show comment and pagebreak question types
1153
                if ('pagebreak' !== $row['type']) {
1154
                    $content .= ' <th';
1155
                    if ($row['number_of_options'] > 0 && 'percentage' !== $row['type']) {
1156
                        $content .= ' colspan="'.$row['number_of_options'].'"';
1157
                    }
1158
                    $content .= '>';
1159
                    $content .= '<label>';
1160
                    if ($addFilters) {
1161
                        $content .= '<input
1162
                                type="checkbox"
1163
                                name="questions_filter[]" value="'.$row['question_id'].'" checked="checked"/>';
1164
                    }
1165
                    $content .= $row['survey_question'];
1166
                    $content .= '</label>';
1167
                    $content .= '</th>';
1168
                }
1169
                // No column at all if it's not a question
1170
            }
1171
            $questions[$row['question_id']] = $row;
1172
        }
1173
        $content .= '	</tr>';
1174
1175
        // Getting all the questions and options
1176
        $content .= '	<tr>';
1177
        $content .= '		<th>&nbsp;</th>'; // the user column
1178
1179
        if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter'] ||
1180
            isset($_POST['export_report']) && $_POST['export_report']) || !empty($_POST['fields_filter'])
1181
        ) {
1182
            if ($addExtraFields) {
1183
                // show the fields names for user fields
1184
                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...
1185
                    $content .= '<th>'.$field[3].'</th>';
1186
                }
1187
            }
1188
        }
1189
1190
        // cells with option (none for open question)
1191
        $sql = "SELECT
1192
                    sq.iid question_id,
1193
                    sq.survey_id,
1194
                    sq.survey_question,
1195
                    sq.display,
1196
                    sq.sort,
1197
                    sq.type,
1198
                    sqo.iid question_option_id,
1199
                    sqo.option_text,
1200
                    sqo.sort as option_sort
1201
				FROM $table_survey_question sq
1202
				LEFT JOIN $table_survey_question_option sqo
1203
				ON sq.iid = sqo.question_id
1204
				WHERE
1205
				    survey_question NOT LIKE '%{{%' AND
1206
				    sq.survey_id = $surveyId
1207
				ORDER BY sq.sort ASC, sqo.sort ASC";
1208
        $result = Database::query($sql);
1209
1210
        $display_percentage_header = 1;
1211
        $possible_answers = [];
1212
        // in order to display only once the cell option (and not 100 times)
1213
        while ($row = Database::fetch_array($result)) {
1214
            // We show the options if
1215
            // 1. there is no question filter and the export button has not been clicked
1216
            // 2. there is a question filter but the question is selected for display
1217
            if (!(isset($_POST['submit_question_filter']) && $_POST['submit_question_filter']) ||
1218
                (is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter']))
1219
            ) {
1220
                // we do not show comment and pagebreak question types
1221
                if ('open' == $row['type'] || 'comment' == $row['type']) {
1222
                    $content .= '<th>&nbsp;-&nbsp;</th>';
1223
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1224
                    $display_percentage_header = 1;
1225
                } elseif ('percentage' == $row['type'] && $display_percentage_header) {
1226
                    $content .= '<th>&nbsp;%&nbsp;</th>';
1227
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1228
                    $display_percentage_header = 0;
1229
                } elseif ('percentage' == $row['type']) {
1230
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1231
                } elseif ('pagebreak' != $row['type'] && 'percentage' != $row['type']) {
1232
                    $content .= '<th>';
1233
                    $content .= $row['option_text'];
1234
                    $content .= '</th>';
1235
                    $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id'];
1236
                    $display_percentage_header = 1;
1237
                }
1238
            }
1239
        }
1240
1241
        $content .= '	</tr>';
1242
1243
        $userCondition = '';
1244
        if (!empty($userId)) {
1245
            $userId = (int) $userId;
1246
            $userCondition = " AND user = $userId ";
1247
        }
1248
1249
        // Getting all the answers of the users
1250
        $old_user = '';
1251
        $answers_of_user = [];
1252
        $sql = "SELECT * FROM $table_survey_answer
1253
                WHERE
1254
                    survey_id = $surveyId
1255
                    $userCondition
1256
                    $sessionCondition
1257
                    $lpItemCondition
1258
                ORDER BY iid, user ASC";
1259
        $result = Database::query($sql);
1260
        $i = 1;
1261
        while ($row = Database::fetch_array($result)) {
1262
            if ($old_user != $row['user'] && '' != $old_user) {
1263
                $userParam = $old_user;
1264
                if (0 != $survey->getAnonymous()) {
1265
                    $userParam = $i;
1266
                    $i++;
1267
                }
1268
                $content .= self::display_complete_report_row(
1269
                    $survey,
1270
                    $possible_answers,
1271
                    $answers_of_user,
1272
                    $userParam,
1273
                    $questions,
1274
                    $display_extra_user_fields
1275
                );
1276
                $answers_of_user = [];
1277
            }
1278
            if (isset($questions[$row['question_id']]) &&
1279
                'open' != $questions[$row['question_id']]['type'] &&
1280
                'comment' != $questions[$row['question_id']]['type']
1281
            ) {
1282
                $answers_of_user[$row['question_id']][$row['option_id']] = $row;
1283
            } else {
1284
                $answers_of_user[$row['question_id']][0] = $row;
1285
            }
1286
            $old_user = $row['user'];
1287
        }
1288
1289
        $userParam = $old_user;
1290
        if (0 != $survey->getAnonymous()) {
1291
            $userParam = $i;
1292
            $i++;
1293
        }
1294
1295
        $content .= self::display_complete_report_row(
1296
            $survey,
1297
            $possible_answers,
1298
            $answers_of_user,
1299
            $userParam,
1300
            $questions,
1301
            $display_extra_user_fields
1302
        );
1303
1304
        // This is to display the last user
1305
        $content .= '</table>';
1306
        $content .= '</form>';
1307
1308
        return $content;
1309
    }
1310
1311
    /**
1312
     * Return user answers in a row.
1313
     *
1314
     * @return string
1315
     */
1316
    public static function display_complete_report_row(
1317
        CSurvey $survey,
1318
        $possible_options,
1319
        $answers_of_user,
1320
        $user,
1321
        $questions,
1322
        $display_extra_user_fields = false
1323
    ) {
1324
        $user = Security::remove_XSS($user);
1325
        $surveyId = $survey->getIid();
1326
1327
        if (empty($surveyId)) {
1328
            return '';
1329
        }
1330
1331
        $content = '<tr>';
1332
        $url = api_get_path(WEB_CODE_PATH).'survey/reporting.php?survey_id='.$surveyId.'&'.api_get_cidreq();
1333
        if (0 == $survey->getAnonymous()) {
1334
            if (0 !== (int) $user) {
1335
                $userInfo = api_get_user_info($user);
1336
                $user_displayed = '-';
1337
                if (!empty($userInfo)) {
1338
                    $user_displayed = $userInfo['complete_name_with_username'];
1339
                }
1340
1341
                $content .= '<th>
1342
                    <a href="'.$url.'&action=userreport&user='.$user.'">'
0 ignored issues
show
Bug introduced by
Are you sure $user of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

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

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

2090
        $url = api_get_self().'?'.api_get_cidreq().'&action='./** @scrutinizer ignore-type */ Security::remove_XSS($_GET['action'])
Loading history...
2091
            .'&survey_id='.$surveyId.'&xaxis='.$xAxis.'&y='.$yAxis;
0 ignored issues
show
Bug introduced by
Are you sure $xAxis of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

2091
            .'&survey_id='.$surveyId.'&xaxis='./** @scrutinizer ignore-type */ $xAxis.'&y='.$yAxis;
Loading history...
Bug introduced by
Are you sure $yAxis of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

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

2662
                $full_invitation_text = /** @scrutinizer ignore-type */ $full_invitation_text."<br />\r\n<br />\r\n".$text_link;
Loading history...
2663
            }
2664
        }
2665
2666
        // Sending the mail
2667
        $sender_name = api_get_person_name($_user['firstName'], $_user['lastName'], null, PERSON_NAME_EMAIL_ADDRESS);
2668
        $sender_email = $_user['mail'];
2669
        $sender_user_id = api_get_user_id();
2670
2671
        $replyto = [];
2672
        if ('noreply' === api_get_setting('survey_email_sender_noreply')) {
2673
            $noreply = api_get_setting('noreply_email_address');
2674
            if (!empty($noreply)) {
2675
                $replyto['Reply-to'] = $noreply;
2676
                $sender_name = $noreply;
2677
                $sender_email = $noreply;
2678
                $sender_user_id = null;
2679
            }
2680
        }
2681
2682
        // Optionally: finding the e-mail of the course user
2683
        if (is_numeric($invitedUser)) {
2684
            MessageManager::send_message(
2685
                $invitedUser,
2686
                $invitation_title,
2687
                $full_invitation_text,
2688
                [],
2689
                [],
2690
                null,
2691
                null,
2692
                null,
2693
                null,
2694
                $sender_user_id,
2695
                true
2696
            );
2697
        } else {
2698
            @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

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