Passed
Push — 1.11.x ( cb872d...05a9d8 )
by Julito
13:03
created

SurveyManager::validate_survey_hash()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 5
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CourseBundle\Entity\CSurveyInvitation;
6
7
/**
8
 * Class SurveyManager.
9
 *
10
 * @author Patrick Cool <[email protected]>, Ghent University:
11
 * cleanup, refactoring and rewriting large parts (if not all) of the code
12
 * @author Julio Montoya <[email protected]>, Personality Test modification
13
 * and rewriting large parts of the code
14
 * @author cfasanando
15
 *
16
 * @todo move this file to inc/lib
17
 * @todo use consistent naming for the functions (save vs store for instance)
18
 */
19
class SurveyManager
20
{
21
    /**
22
     * @param $code
23
     *
24
     * @return string
25
     */
26
    public static function generate_unique_code($code)
27
    {
28
        if (empty($code)) {
29
            return false;
30
        }
31
        $course_id = api_get_course_int_id();
32
        $table = Database::get_course_table(TABLE_SURVEY);
33
        $code = Database::escape_string($code);
34
        $num = 0;
35
        $new_code = $code;
36
        while (true) {
37
            $sql = "SELECT * FROM $table
38
                    WHERE code = '$new_code' AND c_id = $course_id";
39
            $result = Database::query($sql);
40
            if (Database::num_rows($result)) {
41
                $num++;
42
                $new_code = $code.$num;
43
            } else {
44
                break;
45
            }
46
        }
47
48
        return $code.$num;
49
    }
50
51
    /**
52
     * Deletes all survey invitations of a user.
53
     *
54
     * @param int $user_id
55
     *
56
     * @return bool
57
     * @assert ('') === false
58
     */
59
    public static function delete_all_survey_invitations_by_user($user_id)
60
    {
61
        $user_id = (int) $user_id;
62
        if (empty($user_id)) {
63
            return false;
64
        }
65
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
66
        $table_survey = Database::get_course_table(TABLE_SURVEY);
67
68
        $sql = "SELECT survey_invitation_id, survey_code
69
                FROM $table_survey_invitation WHERE user = '$user_id' AND c_id <> 0 ";
70
        $result = Database::query($sql);
71
        while ($row = Database::fetch_array($result, 'ASSOC')) {
72
            $survey_invitation_id = $row['survey_invitation_id'];
73
            $survey_code = $row['survey_code'];
74
            $sql2 = "DELETE FROM $table_survey_invitation
75
                    WHERE survey_invitation_id = '$survey_invitation_id' AND c_id <> 0";
76
            if (Database::query($sql2)) {
77
                $sql3 = "UPDATE $table_survey SET
78
                            invited = invited-1
79
                        WHERE c_id <> 0 AND code ='$survey_code'";
80
                Database::query($sql3);
81
            }
82
        }
83
    }
84
85
    /**
86
     * @param string $course_code
87
     * @param int    $session_id
88
     *
89
     * @return array
90
     * @assert ('') === false
91
     */
92
    public static function get_surveys($course_code, $session_id = 0)
93
    {
94
        if (empty($course_code)) {
95
            return false;
96
        }
97
        $course_info = api_get_course_info($course_code);
98
99
        if (empty($course_info)) {
100
            return false;
101
        }
102
103
        $sessionCondition = api_get_session_condition($session_id, true, true);
104
105
        $table = Database::get_course_table(TABLE_SURVEY);
106
        $sql = "SELECT * FROM $table
107
                WHERE c_id = {$course_info['real_id']} $sessionCondition ";
108
        $result = Database::query($sql);
109
110
        return Database::store_result($result, 'ASSOC');
111
    }
112
113
    /**
114
     * Retrieves all the survey information.
115
     *
116
     * @param int  $survey_id the id of the survey
117
     * @param bool $shared    this parameter determines if
118
     *                        we have to get the information of a survey from the central (shared) database or from the
119
     *                        course database
120
     * @param string course code optional
121
     *
122
     * @author Patrick Cool <[email protected]>, Ghent University
123
     *
124
     * @version February 2007
125
     * @assert ('') === false
126
     *
127
     * @return array
128
     *
129
     * @todo this is the same function as in create_new_survey.php
130
     */
131
    public static function get_survey(
132
        $survey_id,
133
        $shared = 0,
134
        $course_code = '',
135
        $simple_return = false
136
    ) {
137
        $my_course_id = api_get_course_id();
138
139
        // Table definition
140
        if (!empty($course_code)) {
141
            $my_course_id = $course_code;
142
        } elseif (isset($_GET['course'])) {
143
            $my_course_id = Security::remove_XSS($_GET['course']);
144
        }
145
146
        $courseInfo = api_get_course_info($my_course_id);
147
        $survey_id = (int) $survey_id;
148
        $table_survey = Database::get_course_table(TABLE_SURVEY);
149
150
        if (0 != $shared) {
151
            $table_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
152
            $sql = "SELECT * FROM $table_survey
153
                    WHERE survey_id='".$survey_id."' ";
154
        } else {
155
            if (empty($courseInfo)) {
156
                return [];
157
            }
158
            $sql = "SELECT * FROM $table_survey
159
		            WHERE
160
		                survey_id='".$survey_id."' AND
161
		                c_id = ".$courseInfo['real_id'];
162
        }
163
164
        $result = Database::query($sql);
165
        $return = [];
166
167
        if (Database::num_rows($result) > 0) {
168
            $return = Database::fetch_array($result, 'ASSOC');
169
            if ($simple_return) {
170
                return $return;
171
            }
172
            // We do this (temporarily) to have the array match the quickform elements immediately
173
            // idealiter the fields in the db match the quickform fields
174
            $return['survey_code'] = $return['code'];
175
            $return['survey_title'] = $return['title'];
176
            $return['survey_subtitle'] = $return['subtitle'];
177
            $return['survey_language'] = $return['lang'];
178
            $return['start_date'] = $return['avail_from'];
179
            $return['end_date'] = $return['avail_till'];
180
            $return['survey_share'] = $return['is_shared'];
181
            $return['survey_introduction'] = $return['intro'];
182
            $return['survey_thanks'] = $return['surveythanks'];
183
            $return['survey_type'] = $return['survey_type'];
184
            $return['one_question_per_page'] = $return['one_question_per_page'];
185
            $return['show_form_profile'] = $return['show_form_profile'];
186
            $return['input_name_list'] = isset($return['input_name_list']) ? $return['input_name_list'] : null;
187
            $return['shuffle'] = $return['shuffle'];
188
            $return['parent_id'] = $return['parent_id'];
189
            $return['survey_version'] = $return['survey_version'];
190
            $return['anonymous'] = $return['anonymous'];
191
            $return['c_id'] = isset($return['c_id']) ? $return['c_id'] : 0;
192
            $return['session_id'] = isset($return['session_id']) ? $return['session_id'] : 0;
193
        }
194
195
        return $return;
196
    }
197
198
    /**
199
     * @param string $code
200
     *
201
     * @return string
202
     */
203
    public static function generateSurveyCode($code)
204
    {
205
        return strtolower(CourseManager::generate_course_code($code));
206
    }
207
208
    /**
209
     * This function stores a survey in the database.
210
     *
211
     * @param array $values
212
     *
213
     * @return array $return the type of return message that has to be displayed and the message in it
214
     *
215
     * @author Patrick Cool <[email protected]>, Ghent University
216
     *
217
     * @version February 2007
218
     */
219
    public static function store_survey($values)
220
    {
221
        $allowSurveyAvailabilityDatetime = api_get_configuration_value('allow_survey_availability_datetime');
222
        $_user = api_get_user_info();
223
        $course_id = api_get_course_int_id();
224
        $session_id = api_get_session_id();
225
        $courseCode = api_get_course_id();
226
        $table_survey = Database::get_course_table(TABLE_SURVEY);
227
        $shared_survey_id = 0;
228
229
        if (!isset($values['survey_id'])) {
230
            // Check if the code doesn't soon exists in this language
231
            $sql = 'SELECT 1 FROM '.$table_survey.'
232
			        WHERE
233
			            c_id = '.$course_id.' AND
234
			            code = "'.Database::escape_string($values['survey_code']).'" AND
235
			            lang = "'.Database::escape_string($values['survey_language']).'"';
236
            $rs = Database::query($sql);
237
            if (Database::num_rows($rs) > 0) {
238
                Display::addFlash(
239
                    Display::return_message(
240
                        get_lang('ThisSurveyCodeSoonExistsInThisLanguage'),
241
                        'error'
242
                    )
243
                );
244
                $return['type'] = 'error';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$return was never initialized. Although not strictly required by PHP, it is generally a good practice to add $return = array(); before regardless.
Loading history...
245
                $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0;
246
247
                return $return;
248
            }
249
250
            if (!isset($values['anonymous'])) {
251
                $values['anonymous'] = 0;
252
            }
253
254
            $values['anonymous'] = (int) $values['anonymous'];
255
            $extraParams = [];
256
            if ($values['anonymous'] == 0) {
257
                // Input_name_list
258
                $values['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0;
259
                $extraParams['show_form_profile'] = $values['show_form_profile'];
260
261
                if ($values['show_form_profile'] == 1) {
262
                    // Input_name_list
263
                    $fields = explode(',', $values['input_name_list']);
264
                    $field_values = '';
265
                    foreach ($fields as &$field) {
266
                        if ($field != '') {
267
                            if ($values[$field] == '') {
268
                                $values[$field] = 0;
269
                            }
270
                            $field_values .= $field.':'.$values[$field].'@';
271
                        }
272
                    }
273
                    $extraParams['form_fields'] = $field_values;
274
                } else {
275
                    $extraParams['form_fields'] = '';
276
                }
277
            } else {
278
                // Input_name_list
279
                $extraParams['show_form_profile'] = 0;
280
                $extraParams['form_fields'] = '';
281
            }
282
283
            $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0;
284
            $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : 0;
285
286
            if ($values['survey_type'] == 1) {
287
                $extraParams['survey_type'] = 1;
288
                $extraParams['parent_id'] = $values['parent_id'];
289
290
                // Logic for versioning surveys
291
                if (!empty($values['parent_id'])) {
292
                    $versionValue = '';
293
                    $sql = 'SELECT survey_version
294
                            FROM '.$table_survey.'
295
					        WHERE
296
					            c_id = '.$course_id.' AND
297
					            parent_id = '.intval($values['parent_id']).'
298
                            ORDER BY survey_version DESC
299
                            LIMIT 1';
300
                    $rs = Database::query($sql);
301
                    if (Database::num_rows($rs) === 0) {
302
                        $sql = 'SELECT survey_version FROM '.$table_survey.'
303
						        WHERE
304
						            c_id = '.$course_id.' AND
305
						            survey_id = '.intval($values['parent_id']);
306
                        $rs = Database::query($sql);
307
                        $getversion = Database::fetch_array($rs, 'ASSOC');
308
                        if (empty($getversion['survey_version'])) {
309
                            $versionValue = ++$getversion['survey_version'];
310
                        } else {
311
                            $versionValue = $getversion['survey_version'];
312
                        }
313
                    } else {
314
                        $row = Database::fetch_array($rs, 'ASSOC');
315
                        $pos = api_strpos($row['survey_version']);
0 ignored issues
show
Bug introduced by
The call to api_strpos() has too few arguments starting with needle. ( Ignorable by Annotation )

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

315
                        $pos = /** @scrutinizer ignore-call */ api_strpos($row['survey_version']);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
316
                        if ($pos === false) {
317
                            $row['survey_version'] = $row['survey_version'] + 1;
318
                            $versionValue = $row['survey_version'];
319
                        } else {
320
                            $getlast = explode('\.', $row['survey_version']);
321
                            $lastversion = array_pop($getlast);
322
                            $lastversion = $lastversion + 1;
323
                            $add = implode('.', $getlast);
324
                            if ($add != '') {
325
                                $insertnewversion = $add.'.'.$lastversion;
326
                            } else {
327
                                $insertnewversion = $lastversion;
328
                            }
329
                            $versionValue = $insertnewversion;
330
                        }
331
                    }
332
                    $extraParams['survey_version'] = $versionValue;
333
                }
334
            }
335
336
            $params = [
337
                'c_id' => $course_id,
338
                'code' => self::generateSurveyCode($values['survey_code']),
339
                'title' => $values['survey_title'],
340
                'subtitle' => $values['survey_subtitle'],
341
                'author' => $_user['user_id'],
342
                'lang' => $values['survey_language'],
343
                'is_shared' => $shared_survey_id,
344
                'template' => 'template',
345
                'intro' => $values['survey_introduction'],
346
                'surveythanks' => $values['survey_thanks'],
347
                'creation_date' => api_get_utc_datetime(),
348
                'anonymous' => $values['anonymous'],
349
                'session_id' => api_get_session_id(),
350
                'visible_results' => $values['visible_results'],
351
            ];
352
353
            if (!empty($values['start_date'])) {
354
                if ($allowSurveyAvailabilityDatetime) {
355
                    $params['avail_from'] = api_get_utc_datetime($values['start_date'].':00');
356
                } else {
357
                    $params['avail_from'] = $values['start_date'];
358
                }
359
            }
360
361
            if (!empty($values['end_date'])) {
362
                if ($allowSurveyAvailabilityDatetime) {
363
                    $params['avail_till'] = api_get_utc_datetime($values['end_date'].':00');
364
                } else {
365
                    $params['avail_till'] = $values['end_date'];
366
                }
367
            }
368
369
            if (isset($values['survey_type']) && !empty($values['survey_type'])) {
370
                $params['survey_type'] = $values['survey_type'];
371
            }
372
373
            $params = array_merge($params, $extraParams);
374
375
            $survey_id = Database::insert($table_survey, $params);
376
            if ($survey_id > 0) {
377
                Event::addEvent(
0 ignored issues
show
Bug introduced by
The method addEvent() does not exist on Event. ( Ignorable by Annotation )

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

377
                Event::/** @scrutinizer ignore-call */ 
378
                       addEvent(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
378
                    LOG_SURVEY_CREATED,
379
                    LOG_SURVEY_ID,
380
                    $survey_id,
381
                    null,
382
                    api_get_user_id(),
383
                    api_get_course_int_id(),
384
                    api_get_session_id()
385
                );
386
387
                $sql = "UPDATE $table_survey SET survey_id = $survey_id
388
                        WHERE iid = $survey_id";
389
                Database::query($sql);
390
391
                // Insert into item_property
392
                api_item_property_update(
393
                    api_get_course_info(),
394
                    TOOL_SURVEY,
395
                    $survey_id,
396
                    'SurveyAdded',
397
                    api_get_user_id()
398
                );
399
            }
400
401
            if ($values['survey_type'] == 1 && !empty($values['parent_id'])) {
402
                self::copy_survey($values['parent_id'], $survey_id);
403
            }
404
405
            Display::addFlash(
406
                Display::return_message(
407
                    get_lang('SurveyCreatedSuccesfully'),
408
                    'success'
409
                )
410
            );
411
            $return['id'] = $survey_id;
412
        } else {
413
            // Check whether the code doesn't soon exists in this language
414
            $sql = 'SELECT 1 FROM '.$table_survey.'
415
			        WHERE
416
			            c_id = '.$course_id.' AND
417
			            code = "'.Database::escape_string($values['survey_code']).'" AND
418
			            lang = "'.Database::escape_string($values['survey_language']).'" AND
419
			            survey_id !='.intval($values['survey_id']);
420
            $rs = Database::query($sql);
421
            if (Database::num_rows($rs) > 0) {
422
                Display::addFlash(
423
                    Display::return_message(
424
                        get_lang('ThisSurveyCodeSoonExistsInThisLanguage'),
425
                        'error'
426
                    )
427
                );
428
                $return['type'] = 'error';
429
                $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0;
430
431
                return $return;
432
            }
433
434
            if (!isset($values['anonymous'])
435
                || (isset($values['anonymous']) && $values['anonymous'] == '')
436
            ) {
437
                $values['anonymous'] = 0;
438
            }
439
440
            $extraParams = [];
441
            $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0;
442
            $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : 0;
443
444
            if ($values['anonymous'] == 0) {
445
                $extraParams['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0;
446
                if ($extraParams['show_form_profile'] == 1) {
447
                    $fields = explode(',', $values['input_name_list']);
448
                    $field_values = '';
449
                    foreach ($fields as &$field) {
450
                        if ($field != '') {
451
                            if (!isset($values[$field]) ||
452
                                (isset($values[$field]) && $values[$field] == '')
453
                            ) {
454
                                $values[$field] = 0;
455
                            }
456
                            $field_values .= $field.':'.$values[$field].'@';
457
                        }
458
                    }
459
                    $extraParams['form_fields'] = $field_values;
460
                } else {
461
                    $extraParams['form_fields'] = '';
462
                }
463
            } else {
464
                $extraParams['show_form_profile'] = 0;
465
                $extraParams['form_fields'] = '';
466
            }
467
468
            $params = [
469
                'title' => $values['survey_title'],
470
                'subtitle' => $values['survey_subtitle'],
471
                'author' => $_user['user_id'],
472
                'lang' => $values['survey_language'],
473
                'avail_from' => $allowSurveyAvailabilityDatetime
474
                    ? api_get_utc_datetime($values['start_date'].':00')
475
                    : $values['start_date'],
476
                'avail_till' => $allowSurveyAvailabilityDatetime
477
                    ? api_get_utc_datetime($values['end_date'].':59')
478
                    : $values['end_date'],
479
                'is_shared' => $shared_survey_id,
480
                'template' => 'template',
481
                'intro' => $values['survey_introduction'],
482
                'surveythanks' => $values['survey_thanks'],
483
                'anonymous' => $values['anonymous'],
484
                'session_id' => api_get_session_id(),
485
                'visible_results' => $values['visible_results'],
486
            ];
487
488
            $params = array_merge($params, $extraParams);
489
            Database::update(
490
                $table_survey,
491
                $params,
492
                [
493
                    'c_id = ? AND survey_id = ?' => [
494
                        $course_id,
495
                        $values['survey_id'],
496
                    ],
497
                ]
498
            );
499
500
            // Update into item_property (update)
501
            api_item_property_update(
502
                api_get_course_info(),
503
                TOOL_SURVEY,
504
                $values['survey_id'],
505
                'SurveyUpdated',
506
                api_get_user_id()
507
            );
508
509
            Display::addFlash(
510
                Display::return_message(
511
                    get_lang('SurveyUpdatedSuccesfully'),
512
                    'confirmation'
513
                )
514
            );
515
516
            $return['id'] = $values['survey_id'];
517
        }
518
519
        $survey_id = (int) $return['id'];
520
521
        // Gradebook
522
        $gradebook_option = false;
523
        if (isset($values['survey_qualify_gradebook'])) {
524
            $gradebook_option = $values['survey_qualify_gradebook'] > 0;
525
        }
526
527
        $gradebook_link_type = 8;
528
        $link_info = GradebookUtils::isResourceInCourseGradebook(
529
            $courseCode,
530
            $gradebook_link_type,
531
            $survey_id,
532
            $session_id
533
        );
534
535
        $gradebook_link_id = isset($link_info['id']) ? $link_info['id'] : false;
536
537
        if ($gradebook_option) {
538
            if ($survey_id > 0) {
539
                $title_gradebook = ''; // Not needed here.
540
                $description_gradebook = ''; // Not needed here.
541
                $survey_weight = floatval($_POST['survey_weight']);
542
                $max_score = 1;
543
544
                if (!$gradebook_link_id) {
545
                    GradebookUtils::add_resource_to_course_gradebook(
546
                        $values['category_id'],
547
                        $courseCode,
548
                        $gradebook_link_type,
549
                        $survey_id,
550
                        $title_gradebook,
551
                        $survey_weight,
552
                        $max_score,
553
                        $description_gradebook,
554
                        1,
555
                        $session_id
556
                    );
557
                } else {
558
                    GradebookUtils::updateResourceFromCourseGradebook(
559
                        $gradebook_link_id,
560
                        $courseCode,
561
                        $survey_weight
562
                    );
563
                }
564
            }
565
        } else {
566
            // Delete everything of the gradebook for this $linkId
567
            GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id);
568
        }
569
570
        return $return;
571
    }
572
573
    /**
574
     * This function stores a shared survey in the central database.
575
     *
576
     * @param array $values
577
     *
578
     * @return array $return the type of return message that has to be displayed and the message in it
579
     *
580
     * @author Patrick Cool <[email protected]>, Ghent University
581
     *
582
     * @version February 2007
583
     */
584
    public function store_shared_survey($values)
585
    {
586
        $_user = api_get_user_info();
587
        $_course = api_get_course_info();
588
589
        // Table definitions
590
        $table_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
591
592
        if (!$values['survey_id'] ||
593
            !is_numeric($values['survey_id']) ||
594
            'true' == $values['survey_share']['survey_share']
595
        ) {
596
            $sql = "INSERT INTO $table_survey (code, title, subtitle, author, lang, template, intro, surveythanks, creation_date, course_code) VALUES (
597
                    '".Database::escape_string($values['survey_code'])."',
598
                    '".Database::escape_string($values['survey_title'])."',
599
                    '".Database::escape_string($values['survey_subtitle'])."',
600
                    '".intval($_user['user_id'])."',
601
                    '".Database::escape_string($values['survey_language'])."',
602
                    '".Database::escape_string('template')."',
603
                    '".Database::escape_string($values['survey_introduction'])."',
604
                    '".Database::escape_string($values['survey_thanks'])."',
605
                    '".api_get_utc_datetime()."',
606
                    '".$_course['id']."')";
607
            Database::query($sql);
608
            $return = Database::insert_id();
609
610
            $sql = "UPDATE $table_survey SET survey_id = $return WHERE iid = $return";
611
            Database::query($sql);
612
        } else {
613
            $sql = "UPDATE $table_survey SET
614
                        code 			= '".Database::escape_string($values['survey_code'])."',
615
                        title 			= '".Database::escape_string($values['survey_title'])."',
616
                        subtitle 		= '".Database::escape_string($values['survey_subtitle'])."',
617
                        author 			= '".intval($_user['user_id'])."',
618
                        lang 			= '".Database::escape_string($values['survey_language'])."',
619
                        template 		= '".Database::escape_string('template')."',
620
                        intro			= '".Database::escape_string($values['survey_introduction'])."',
621
                        surveythanks	= '".Database::escape_string($values['survey_thanks'])."'
622
					WHERE survey_id = '".Database::escape_string($values['survey_share']['survey_share'])."'";
623
            Database::query($sql);
624
            $return = $values['survey_share']['survey_share'];
625
        }
626
627
        return $return;
628
    }
629
630
    /**
631
     * This function deletes a survey (and also all the question in that survey.
632
     *
633
     * @param int  $survey_id id of the survey that has to be deleted
634
     * @param bool $shared
635
     * @param int  $course_id
636
     *
637
     * @return true
638
     *
639
     * @author Patrick Cool <[email protected]>, Ghent University
640
     *
641
     * @version January 2007
642
     */
643
    public static function delete_survey($survey_id, $shared = false, $course_id = 0)
644
    {
645
        // Database table definitions
646
        if (empty($course_id)) {
647
            $course_id = api_get_course_int_id();
648
        }
649
650
        $survey_id = (int) $survey_id;
651
652
        if (empty($survey_id)) {
653
            return false;
654
        }
655
656
        $course_info = api_get_course_info_by_id($course_id);
657
        $course_id = $course_info['real_id'];
658
659
        $table_survey = Database::get_course_table(TABLE_SURVEY);
660
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
661
662
        if ($shared) {
663
            $table_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
664
            // Deleting the survey
665
            $sql = "DELETE FROM $table_survey
666
                    WHERE survey_id='".$survey_id."'";
667
            Database::query($sql);
668
        } else {
669
            $sql = "DELETE FROM $table_survey
670
                    WHERE c_id = $course_id AND survey_id='".$survey_id."'";
671
            Database::query($sql);
672
        }
673
674
        Event::addEvent(
675
            LOG_SURVEY_DELETED,
676
            LOG_SURVEY_ID,
677
            $survey_id,
678
            null,
679
            api_get_user_id(),
680
            api_get_course_int_id(),
681
            api_get_session_id()
682
        );
683
684
        // Deleting groups of this survey
685
        $sql = "DELETE FROM $table_survey_question_group
686
                WHERE c_id = $course_id AND survey_id='".$survey_id."'";
687
        Database::query($sql);
688
689
        // Deleting the questions of the survey
690
        self::delete_all_survey_questions($survey_id, $shared);
691
692
        // Update into item_property (delete)
693
        api_item_property_update(
694
            $course_info,
695
            TOOL_SURVEY,
696
            $survey_id,
697
            'SurveyDeleted',
698
            api_get_user_id()
699
        );
700
701
        Skill::deleteSkillsFromItem($survey_id, ITEM_TYPE_SURVEY);
702
703
        return true;
704
    }
705
706
    /**
707
     * Copy given survey to a new (optional) given survey ID.
708
     *
709
     * @param int $survey_id
710
     * @param int $new_survey_id
711
     * @param int $targetCourseId
712
     *
713
     * @return bool
714
     */
715
    public static function copy_survey(
716
        $survey_id,
717
        $new_survey_id = null,
718
        $targetCourseId = null
719
    ) {
720
        $course_id = api_get_course_int_id();
721
        if (!$targetCourseId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $targetCourseId of type integer|null is loosely compared to false; 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...
722
            $targetCourseId = $course_id;
723
        }
724
725
        // Database table definitions
726
        $table_survey = Database::get_course_table(TABLE_SURVEY);
727
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
728
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
729
        $table_survey_options = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
730
        $survey_id = (int) $survey_id;
731
732
        // Get groups
733
        $survey_data = self::get_survey($survey_id, 0, null, true);
734
        if (empty($survey_data)) {
735
            return true;
736
        }
737
738
        if (empty($new_survey_id)) {
739
            $params = $survey_data;
740
            $params['code'] = self::generate_unique_code($params['code']);
741
            $params['c_id'] = $targetCourseId;
742
            unset($params['survey_id']);
743
            $params['session_id'] = api_get_session_id();
744
            $params['title'] = $params['title'].' '.get_lang('Copy');
745
            unset($params['iid']);
746
            $params['invited'] = 0;
747
            $params['answered'] = 0;
748
            $new_survey_id = Database::insert($table_survey, $params);
749
750
            if ($new_survey_id) {
751
                $sql = "UPDATE $table_survey SET survey_id = $new_survey_id
752
                        WHERE iid = $new_survey_id";
753
                Database::query($sql);
754
755
                // Insert into item_property
756
                api_item_property_update(
757
                    api_get_course_info(),
758
                    TOOL_SURVEY,
759
                    $new_survey_id,
760
                    'SurveyAdded',
761
                    api_get_user_id()
762
                );
763
            }
764
        } else {
765
            $new_survey_id = (int) $new_survey_id;
766
        }
767
768
        $sql = "SELECT * FROM $table_survey_question_group
769
                WHERE c_id = $course_id AND survey_id = $survey_id";
770
        $res = Database::query($sql);
771
        while ($row = Database::fetch_array($res, 'ASSOC')) {
772
            $params = [
773
                'c_id' => $targetCourseId,
774
                'name' => $row['name'],
775
                'description' => $row['description'],
776
                'survey_id' => $new_survey_id,
777
            ];
778
            $insertId = Database::insert($table_survey_question_group, $params);
779
780
            $sql = "UPDATE $table_survey_question_group SET id = iid
781
                    WHERE iid = $insertId";
782
            Database::query($sql);
783
784
            $group_id[$row['id']] = $insertId;
785
        }
786
787
        // Get questions
788
        $sql = "SELECT * FROM $table_survey_question
789
                WHERE c_id = $course_id AND survey_id = $survey_id";
790
        $res = Database::query($sql);
791
        while ($row = Database::fetch_array($res, 'ASSOC')) {
792
            $params = [
793
                'c_id' => $targetCourseId,
794
                'survey_id' => $new_survey_id,
795
                'survey_question' => $row['survey_question'],
796
                'survey_question_comment' => $row['survey_question_comment'],
797
                'type' => $row['type'],
798
                'display' => $row['display'],
799
                'sort' => $row['sort'],
800
                'shared_question_id' => $row['shared_question_id'],
801
                'max_value' => $row['max_value'],
802
                'survey_group_pri' => $row['survey_group_pri'],
803
                'survey_group_sec1' => $row['survey_group_sec1'],
804
                'survey_group_sec2' => $row['survey_group_sec2'],
805
            ];
806
807
            if (api_get_configuration_value('allow_required_survey_questions')) {
808
                if (isset($row['is_required'])) {
809
                    $params['is_required'] = $row['is_required'];
810
                }
811
            }
812
813
            $insertId = Database::insert($table_survey_question, $params);
814
            if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
815
                $sql = "UPDATE $table_survey_question SET question_id = iid WHERE iid = $insertId";
816
                Database::query($sql);
817
                $question_id[$row['question_id']] = $insertId;
818
            }
819
        }
820
821
        // Get questions options
822
        $sql = "SELECT * FROM $table_survey_options
823
                WHERE c_id = $course_id AND survey_id='".$survey_id."'";
824
825
        $res = Database::query($sql);
826
        while ($row = Database::fetch_array($res, 'ASSOC')) {
827
            $params = [
828
                'c_id' => $targetCourseId,
829
                'question_id' => $question_id[$row['question_id']],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
830
                'survey_id' => $new_survey_id,
831
                'option_text' => $row['option_text'],
832
                'sort' => $row['sort'],
833
                'value' => $row['value'],
834
            ];
835
            $insertId = Database::insert($table_survey_options, $params);
836
            if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
837
                $sql = "UPDATE $table_survey_options SET question_option_id = $insertId
838
                        WHERE iid = $insertId";
839
                Database::query($sql);
840
            }
841
        }
842
843
        return $new_survey_id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $new_survey_id also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
844
    }
845
846
    /**
847
     * This function duplicates a survey (and also all the question in that survey.
848
     *
849
     * @param int $surveyId id of the survey that has to be duplicated
850
     * @param int $courseId id of the course which survey has to be duplicated
851
     *
852
     * @return true
853
     *
854
     * @author Eric Marguin <[email protected]>, Elixir Interactive
855
     *
856
     * @version October 2007
857
     */
858
    public static function empty_survey($surveyId, $courseId = 0)
859
    {
860
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
861
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
862
        $table_survey = Database::get_course_table(TABLE_SURVEY);
863
864
        $courseId = (int) $courseId;
865
        $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
866
        $surveyId = (int) $surveyId;
867
868
        $datas = self::get_survey($surveyId);
869
        $session_where = '';
870
        if (0 != api_get_session_id()) {
871
            $session_where = ' AND session_id = "'.api_get_session_id().'" ';
872
        }
873
874
        $sql = 'DELETE FROM '.$table_survey_invitation.'
875
		        WHERE
876
		            c_id = '.$courseId.' AND
877
		            survey_code = "'.Database::escape_string($datas['code']).'" '.$session_where.' ';
878
        Database::query($sql);
879
880
        $sql = 'DELETE FROM '.$table_survey_answer.'
881
		        WHERE c_id = '.$courseId.' AND survey_id='.$surveyId;
882
        Database::query($sql);
883
884
        $sql = 'UPDATE '.$table_survey.' SET invited=0, answered=0
885
		        WHERE c_id = '.$courseId.' AND survey_id='.$surveyId;
886
        Database::query($sql);
887
888
        Event::addEvent(
889
            LOG_SURVEY_CLEAN_RESULTS,
890
            LOG_SURVEY_ID,
891
            $surveyId,
892
            null,
893
            api_get_user_id(),
894
            api_get_course_int_id(),
895
            api_get_session_id()
896
        );
897
898
        return true;
899
    }
900
901
    /**
902
     * This function recalculates the number of people who have taken the survey (=filled at least one question).
903
     *
904
     * @param array  $survey_data
905
     * @param array  $user
906
     * @param string $survey_code
907
     *
908
     * @return bool
909
     *
910
     * @author Patrick Cool <[email protected]>, Ghent University
911
     *
912
     * @version February 2007
913
     */
914
    public static function update_survey_answered($survey_data, $user, $survey_code)
915
    {
916
        if (empty($survey_data)) {
917
            return false;
918
        }
919
920
        // Database table definitions
921
        $table_survey = Database::get_course_table(TABLE_SURVEY);
922
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
923
924
        $survey_id = (int) $survey_data['survey_id'];
925
        $course_id = (int) $survey_data['c_id'];
926
        $session_id = $survey_data['session_id'];
927
928
        // Getting a list with all the people who have filled the survey
929
        /*$people_filled = self::get_people_who_filled_survey($survey_id, false, $course_id);
930
        $number = count($people_filled);*/
931
932
        // Storing this value in the survey table
933
        $sql = "UPDATE $table_survey
934
		        SET answered = answered + 1
935
		        WHERE
936
                    c_id = $course_id AND
937
		            survey_id = ".$survey_id;
938
        Database::query($sql);
939
940
        $allow = api_get_configuration_value('survey_answered_at_field');
941
        // Requires DB change:
942
        // ALTER TABLE c_survey_invitation ADD answered_at DATETIME DEFAULT NULL;
943
        $answeredAt = '';
944
        if ($allow) {
945
            $answeredAt = "answered_at = '".api_get_utc_datetime()."',";
946
        }
947
948
        // Storing that the user has finished the survey.
949
        $sql = "UPDATE $table_survey_invitation
950
                SET $answeredAt answered = 1
951
                WHERE
952
                    c_id = $course_id AND
953
                    session_id = $session_id AND
954
                    user ='".Database::escape_string($user)."' AND
955
                    survey_code='".Database::escape_string($survey_code)."'";
956
        Database::query($sql);
957
    }
958
959
    /**
960
     * This function return the "icon" of the question type.
961
     *
962
     * @param string $type
963
     *
964
     * @author Patrick Cool <[email protected]>, Ghent University
965
     *
966
     * @version February 2007
967
     */
968
    public static function icon_question($type)
969
    {
970
        // the possible question types
971
        $possible_types = [
972
            'personality',
973
            'yesno',
974
            'multiplechoice',
975
            'multipleresponse',
976
            'open',
977
            'dropdown',
978
            'comment',
979
            'pagebreak',
980
            'percentage',
981
            'score',
982
        ];
983
984
        // the images array
985
        $icon_question = [
986
            'yesno' => 'yesno.png',
987
            'personality' => 'yesno.png',
988
            'multiplechoice' => 'mcua.png',
989
            'multipleresponse' => 'mcma.png',
990
            'open' => 'open_answer.png',
991
            'dropdown' => 'dropdown.png',
992
            'percentage' => 'percentagequestion.png',
993
            'score' => 'scorequestion.png',
994
            'comment' => 'commentquestion.png',
995
            'pagebreak' => 'page_end.png',
996
        ];
997
998
        if (in_array($type, $possible_types)) {
999
            return $icon_question[$type];
1000
        }
1001
1002
        return false;
1003
    }
1004
1005
    /**
1006
     * This function retrieves all the information of a question.
1007
     *
1008
     * @param int  $question_id the id of the question
1009
     * @param bool $shared
1010
     *
1011
     * @return array
1012
     *
1013
     * @author Patrick Cool <[email protected]>, Ghent University
1014
     *
1015
     * @version January 2007
1016
     *
1017
     * @todo one sql call should do the trick
1018
     */
1019
    public static function get_question($question_id, $shared = false)
1020
    {
1021
        // Table definitions
1022
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1023
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1024
        $course_id = api_get_course_int_id();
1025
        $question_id = (int) $question_id;
1026
1027
        if (empty($question_id)) {
1028
            return [];
1029
        }
1030
1031
        $sql = "SELECT * FROM $tbl_survey_question
1032
                WHERE c_id = $course_id AND question_id = $question_id
1033
                ORDER BY `sort` ";
1034
1035
        $sqlOption = "  SELECT * FROM $table_survey_question_option
1036
                        WHERE c_id = $course_id AND question_id='".$question_id."'
1037
                        ORDER BY `sort` ";
1038
1039
        if ($shared) {
1040
            $tbl_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1041
            $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1042
1043
            $sql = "SELECT * FROM $tbl_survey_question
1044
                    WHERE question_id = $question_id
1045
                    ORDER BY `sort` ";
1046
            $sqlOption = "SELECT * FROM $table_survey_question_option
1047
                          WHERE question_id = $question_id
1048
                          ORDER BY `sort` ";
1049
        }
1050
1051
        // Getting the information of the question
1052
        $result = Database::query($sql);
1053
        $row = Database::fetch_array($result, 'ASSOC');
1054
1055
        $return['survey_id'] = $row['survey_id'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$return was never initialized. Although not strictly required by PHP, it is generally a good practice to add $return = array(); before regardless.
Loading history...
1056
        $return['parent_id'] = isset($row['parent_id']) ? $row['parent_id'] : 0;
1057
        $return['parent_option_id'] = isset($row['parent_option_id']) ? $row['parent_option_id'] : 0;
1058
        $return['question_id'] = $row['question_id'];
1059
        $return['type'] = $row['type'];
1060
        $return['question'] = $row['survey_question'];
1061
        $return['horizontalvertical'] = $row['display'];
1062
        $return['shared_question_id'] = $row['shared_question_id'];
1063
        $return['maximum_score'] = $row['max_value'];
1064
        $return['is_required'] = api_get_configuration_value('allow_required_survey_questions')
1065
            ? $row['is_required']
1066
            : false;
1067
1068
        if (0 != $row['survey_group_pri']) {
1069
            $return['assigned'] = $row['survey_group_pri'];
1070
            $return['choose'] = 1;
1071
        } else {
1072
            $return['assigned1'] = $row['survey_group_sec1'];
1073
            $return['assigned2'] = $row['survey_group_sec2'];
1074
            $return['choose'] = 2;
1075
        }
1076
1077
        // Getting the information of the question options
1078
        $result = Database::query($sqlOption);
1079
        $counter = 0;
1080
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1081
            /** @todo this should be renamed to options instead of answers */
1082
            $return['answers'][] = $row['option_text'];
1083
            $return['values'][] = $row['value'];
1084
            $return['answer_data'][$counter]['data'] = $row['option_text'];
1085
            $return['answer_data'][$counter]['iid'] = $row['iid'];
1086
            /** @todo this can be done more elegantly (used in reporting) */
1087
            $return['answersid'][] = $row['question_option_id'];
1088
            $counter++;
1089
        }
1090
1091
        return $return;
1092
    }
1093
1094
    /**
1095
     * This function gets all the question of any given survey.
1096
     *
1097
     * @param int $surveyId the id of the survey
1098
     * @param int $courseId
1099
     *
1100
     * @return array containing all the questions of the survey
1101
     *
1102
     * @author Patrick Cool <[email protected]>, Ghent University
1103
     *
1104
     * @version February 2007
1105
     *
1106
     * @todo one sql call should do the trick
1107
     */
1108
    public static function get_questions($surveyId, $courseId = 0)
1109
    {
1110
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1111
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1112
1113
        $courseId = (int) $courseId;
1114
        $surveyId = (int) $surveyId;
1115
1116
        if (empty($courseId)) {
1117
            $courseId = api_get_course_int_id();
1118
        }
1119
1120
        // Getting the information of the question
1121
        $sql = "SELECT * FROM $tbl_survey_question
1122
		        WHERE c_id = $courseId AND survey_id= $surveyId ";
1123
        $result = Database::query($sql);
1124
        $questions = [];
1125
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1126
            $questionId = $row['question_id'];
1127
            $questions[$questionId]['survey_id'] = $surveyId;
1128
            $questions[$questionId]['question_id'] = $questionId;
1129
            $questions[$questionId]['type'] = $row['type'];
1130
            $questions[$questionId]['question'] = $row['survey_question'];
1131
            $questions[$questionId]['horizontalvertical'] = $row['display'];
1132
            $questions[$questionId]['maximum_score'] = $row['max_value'];
1133
            $questions[$questionId]['sort'] = $row['sort'];
1134
            $questions[$questionId]['survey_question_comment'] = $row['survey_question_comment'];
1135
1136
            // Getting the information of the question options
1137
            $sql = "SELECT * FROM $table_survey_question_option
1138
		             WHERE c_id = $courseId AND survey_id= $surveyId  AND question_id = $questionId";
1139
            $resultOptions = Database::query($sql);
1140
            while ($rowOption = Database::fetch_array($resultOptions, 'ASSOC')) {
1141
                $questions[$questionId]['answers'][] = $rowOption['option_text'];
1142
            }
1143
        }
1144
1145
        return $questions;
1146
    }
1147
1148
    /**
1149
     * This function saves a question in the database.
1150
     * This can be either an update of an existing survey or storing a new survey.
1151
     *
1152
     * @param array $survey_data
1153
     * @param array $form_content all the information of the form
1154
     *
1155
     * @return string
1156
     *
1157
     * @author Patrick Cool <[email protected]>, Ghent University
1158
     *
1159
     * @version January 2007
1160
     */
1161
    public static function save_question($survey_data, $form_content, $showMessage = true, $dataFromDatabase = [])
1162
    {
1163
        $return_message = '';
1164
        if (strlen($form_content['question']) > 1) {
1165
            // Checks length of the question
1166
            $empty_answer = false;
1167
            if (1 == $survey_data['survey_type']) {
1168
                if (empty($form_content['choose'])) {
1169
                    return 'PleaseChooseACondition';
1170
                }
1171
1172
                if ((2 == $form_content['choose']) &&
1173
                    ($form_content['assigned1'] == $form_content['assigned2'])
1174
                ) {
1175
                    return 'ChooseDifferentCategories';
1176
                }
1177
            }
1178
1179
            if ('percentage' !== $form_content['type']) {
1180
                if (isset($form_content['answers'])) {
1181
                    for ($i = 0; $i < count($form_content['answers']); $i++) {
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...
1182
                        if (strlen($form_content['answers'][$i]) < 1) {
1183
                            $empty_answer = true;
1184
                            break;
1185
                        }
1186
                    }
1187
                }
1188
            }
1189
1190
            if ('score' == $form_content['type']) {
1191
                if (strlen($form_content['maximum_score']) < 1) {
1192
                    $empty_answer = true;
1193
                }
1194
            }
1195
1196
            $course_id = api_get_course_int_id();
1197
1198
            if (!$empty_answer) {
1199
                // Table definitions
1200
                $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1201
                $surveyId = (int) $form_content['survey_id'];
1202
1203
                // Getting all the information of the survey
1204
                $survey_data = self::get_survey($surveyId);
1205
1206
                // Storing the question in the shared database
1207
                if (is_numeric($survey_data['survey_share']) && $survey_data['survey_share'] != 0) {
1208
                    $shared_question_id = self::save_shared_question($form_content, $survey_data);
0 ignored issues
show
Bug Best Practice introduced by
The method SurveyManager::save_shared_question() is not static, but was called statically. ( Ignorable by Annotation )

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

1208
                    /** @scrutinizer ignore-call */ 
1209
                    $shared_question_id = self::save_shared_question($form_content, $survey_data);
Loading history...
1209
                    $form_content['shared_question_id'] = $shared_question_id;
1210
                }
1211
1212
                // Storing a new question
1213
                if ($form_content['question_id'] == '' || !is_numeric($form_content['question_id'])) {
1214
                    // Finding the max sort order of the questions in the given survey
1215
                    $sql = "SELECT max(sort) AS max_sort
1216
					        FROM $tbl_survey_question
1217
                            WHERE c_id = $course_id AND survey_id = $surveyId ";
1218
                    $result = Database::query($sql);
1219
                    $row = Database::fetch_array($result, 'ASSOC');
1220
                    $max_sort = $row['max_sort'];
1221
1222
                    // Some variables defined for survey-test type
1223
                    $extraParams = [];
1224
                    if (isset($_POST['choose'])) {
1225
                        if ($_POST['choose'] == 1) {
1226
                            $extraParams['survey_group_pri'] = $_POST['assigned'];
1227
                        } elseif ($_POST['choose'] == 2) {
1228
                            $extraParams['survey_group_sec1'] = $_POST['assigned1'];
1229
                            $extraParams['survey_group_sec2'] = $_POST['assigned2'];
1230
                        }
1231
                    }
1232
1233
                    $questionComment = isset($form_content['question_comment']) ? $form_content['question_comment'] : '';
1234
                    $maxScore = isset($form_content['maximum_score']) ? $form_content['maximum_score'] : '';
1235
                    $display = isset($form_content['horizontalvertical']) ? $form_content['horizontalvertical'] : '';
1236
1237
                    $params = [
1238
                        'c_id' => $course_id,
1239
                        'survey_id' => $surveyId,
1240
                        'survey_question' => $form_content['question'],
1241
                        'survey_question_comment' => $questionComment,
1242
                        'type' => $form_content['type'],
1243
                        'display' => $display,
1244
                        'sort' => $max_sort + 1,
1245
                        'shared_question_id' => $form_content['shared_question_id'],
1246
                        'max_value' => $maxScore,
1247
                    ];
1248
1249
                    if (api_get_configuration_value('survey_question_dependency')) {
1250
                        $params['parent_id'] = 0;
1251
                        $params['parent_option_id'] = 0;
1252
                        if (isset($form_content['parent_id']) &&
1253
                            isset($form_content['parent_option_id']) &&
1254
                            !empty($form_content['parent_id']) &&
1255
                            !empty($form_content['parent_option_id'])
1256
                        ) {
1257
                            $params['parent_id'] = $form_content['parent_id'];
1258
                            $params['parent_option_id'] = $form_content['parent_option_id'];
1259
                        }
1260
                    }
1261
1262
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1263
                        $params['is_required'] = isset($form_content['is_required']);
1264
                    }
1265
1266
                    $params = array_merge($params, $extraParams);
1267
                    $question_id = Database::insert($tbl_survey_question, $params);
1268
                    if ($question_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $question_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1269
                        $sql = "UPDATE $tbl_survey_question SET question_id = $question_id
1270
                                WHERE iid = $question_id";
1271
                        Database::query($sql);
1272
1273
                        $form_content['question_id'] = $question_id;
1274
                        $return_message = 'QuestionAdded';
1275
                    }
1276
                } else {
1277
                    // Updating an existing question
1278
                    $extraParams = [];
1279
                    if (isset($_POST['choose'])) {
1280
                        if (1 == $_POST['choose']) {
1281
                            $extraParams['survey_group_pri'] = $_POST['assigned'];
1282
                            $extraParams['survey_group_sec1'] = 0;
1283
                            $extraParams['survey_group_sec2'] = 0;
1284
                        } elseif (2 == $_POST['choose']) {
1285
                            $extraParams['survey_group_pri'] = 0;
1286
                            $extraParams['survey_group_sec1'] = $_POST['assigned1'];
1287
                            $extraParams['survey_group_sec2'] = $_POST['assigned2'];
1288
                        }
1289
                    }
1290
1291
                    $maxScore = isset($form_content['maximum_score']) ? $form_content['maximum_score'] : null;
1292
                    $questionComment = isset($form_content['question_comment'])
1293
                        ? $form_content['question_comment']
1294
                        : null;
1295
1296
                    // Adding the question to the survey_question table
1297
                    $params = [
1298
                        'survey_question' => $form_content['question'],
1299
                        'survey_question_comment' => $questionComment,
1300
                        'display' => $form_content['horizontalvertical'],
1301
                    ];
1302
1303
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1304
                        $params['is_required'] = isset($form_content['is_required']);
1305
                    }
1306
1307
                    if (api_get_configuration_value('survey_question_dependency')) {
1308
                        $params['parent_id'] = 0;
1309
                        $params['parent_option_id'] = 0;
1310
                        if (isset($form_content['parent_id']) &&
1311
                            isset($form_content['parent_option_id']) &&
1312
                            !empty($form_content['parent_id']) &&
1313
                            !empty($form_content['parent_option_id'])
1314
                        ) {
1315
                            $params['parent_id'] = $form_content['parent_id'];
1316
                            $params['parent_option_id'] = $form_content['parent_option_id'];
1317
                        }
1318
                    }
1319
1320
                    $params = array_merge($params, $extraParams);
1321
                    Database::update(
1322
                        $tbl_survey_question,
1323
                        $params,
1324
                        [
1325
                            'c_id = ? AND question_id = ?' => [
1326
                                $course_id,
1327
                                $form_content['question_id'],
1328
                            ],
1329
                        ]
1330
                    );
1331
                    $return_message = 'QuestionUpdated';
1332
                }
1333
1334
                if (!empty($form_content['survey_id'])) {
1335
                    // Updating survey
1336
                    api_item_property_update(
1337
                        api_get_course_info(),
1338
                        TOOL_SURVEY,
1339
                        $form_content['survey_id'],
1340
                        'SurveyUpdated',
1341
                        api_get_user_id()
1342
                    );
1343
                }
1344
1345
                // Storing the options of the question
1346
                self::save_question_options($form_content, $survey_data, $dataFromDatabase);
1347
            } else {
1348
                $return_message = 'PleasFillAllAnswer';
1349
            }
1350
        } else {
1351
            $return_message = 'PleaseEnterAQuestion';
1352
        }
1353
1354
        if ($showMessage) {
1355
            if (!empty($return_message)) {
1356
                Display::addFlash(Display::return_message(get_lang($return_message)));
1357
            }
1358
        }
1359
1360
        return $return_message;
1361
    }
1362
1363
    /**
1364
     * This function saves the question in the shared database.
1365
     *
1366
     * @param array $form_content all the information of the form
1367
     * @param array $survey_data  all the information of the survey
1368
     *
1369
     * @author Patrick Cool <[email protected]>, Ghent University
1370
     *
1371
     * @version February 2007
1372
     *
1373
     * @return int
1374
     *
1375
     * @todo editing of a shared question
1376
     */
1377
    public function save_shared_question($form_content, $survey_data)
1378
    {
1379
        $_course = api_get_course_info();
1380
1381
        // Table definitions
1382
        $tbl_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1383
1384
        // Storing a new question
1385
        if ('' == $form_content['shared_question_id'] ||
1386
            !is_numeric($form_content['shared_question_id'])
1387
        ) {
1388
            // Finding the max sort order of the questions in the given survey
1389
            $sql = "SELECT max(sort) AS max_sort FROM $tbl_survey_question
1390
                    WHERE survey_id='".intval($survey_data['survey_share'])."'
1391
                    AND code='".Database::escape_string($_course['id'])."'";
1392
            $result = Database::query($sql);
1393
            $row = Database::fetch_array($result, 'ASSOC');
1394
            $max_sort = $row['max_sort'];
1395
1396
            // Adding the question to the survey_question table
1397
            $sql = "INSERT INTO $tbl_survey_question (survey_id, survey_question, survey_question_comment, type, display, sort, code) VALUES (
1398
                    '".Database::escape_string($survey_data['survey_share'])."',
1399
                    '".Database::escape_string($form_content['question'])."',
1400
                    '".Database::escape_string($form_content['question_comment'])."',
1401
                    '".Database::escape_string($form_content['type'])."',
1402
                    '".Database::escape_string($form_content['horizontalvertical'])."',
1403
                    '".Database::escape_string($max_sort + 1)."',
1404
                    '".Database::escape_string($_course['id'])."')";
1405
            Database::query($sql);
1406
            $shared_question_id = Database::insert_id();
1407
        } else {
1408
            // Updating an existing question
1409
            // adding the question to the survey_question table
1410
            $sql = "UPDATE $tbl_survey_question SET
1411
                        survey_question = '".Database::escape_string($form_content['question'])."',
1412
                        survey_question_comment = '".Database::escape_string($form_content['question_comment'])."',
1413
                        display = '".Database::escape_string($form_content['horizontalvertical'])."'
1414
                    WHERE
1415
                        question_id = '".intval($form_content['shared_question_id'])."' AND
1416
                        code = '".Database::escape_string($_course['id'])."'";
1417
            Database::query($sql);
1418
            $shared_question_id = $form_content['shared_question_id'];
1419
        }
1420
1421
        return $shared_question_id;
1422
    }
1423
1424
    /**
1425
     * This functions moves a question of a survey up or down.
1426
     *
1427
     * @param string $direction
1428
     * @param int    $survey_question_id
1429
     * @param int    $survey_id
1430
     *
1431
     * @author Patrick Cool <[email protected]>, Ghent University
1432
     *
1433
     * @version January 2007
1434
     */
1435
    public static function move_survey_question(
1436
        $direction,
1437
        $survey_question_id,
1438
        $survey_id
1439
    ) {
1440
        // Table definition
1441
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1442
        $course_id = api_get_course_int_id();
1443
1444
        if ('moveup' == $direction) {
1445
            $sort = 'DESC';
1446
        }
1447
        if ('movedown' == $direction) {
1448
            $sort = 'ASC';
1449
        }
1450
1451
        $survey_id = (int) $survey_id;
1452
1453
        // Finding the two questions that needs to be swapped
1454
        $sql = "SELECT * FROM $table_survey_question
1455
		        WHERE c_id = $course_id AND survey_id='".$survey_id."'
1456
		        ORDER BY sort $sort";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sort does not seem to be defined for all execution paths leading up to this point.
Loading history...
1457
        $result = Database::query($sql);
1458
        $found = false;
1459
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1460
            if ($found) {
1461
                $question_id_two = $row['question_id'];
1462
                $question_sort_two = $row['sort'];
1463
                $found = false;
1464
            }
1465
            if ($row['question_id'] == $survey_question_id) {
1466
                $found = true;
1467
                $question_id_one = $row['question_id'];
1468
                $question_sort_one = $row['sort'];
1469
            }
1470
        }
1471
1472
        $sql = "UPDATE $table_survey_question
1473
                SET sort = '".Database::escape_string($question_sort_two)."'
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_sort_two does not seem to be defined for all execution paths leading up to this point.
Loading history...
1474
		        WHERE c_id = $course_id AND question_id='".intval($question_id_one)."'";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_id_one does not seem to be defined for all execution paths leading up to this point.
Loading history...
1475
        Database::query($sql);
1476
1477
        $sql = "UPDATE $table_survey_question
1478
                SET sort = '".Database::escape_string($question_sort_one)."'
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_sort_one does not seem to be defined for all execution paths leading up to this point.
Loading history...
1479
		        WHERE c_id = $course_id AND question_id='".intval($question_id_two)."'";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_id_two does not seem to be defined for all execution paths leading up to this point.
Loading history...
1480
        Database::query($sql);
1481
    }
1482
1483
    /**
1484
     * This function deletes all the questions of a given survey
1485
     * This function is normally only called when a survey is deleted.
1486
     *
1487
     * @param int $survey_id the id of the survey that has to be deleted
1488
     *
1489
     * @return bool
1490
     *
1491
     * @author Patrick Cool <[email protected]>, Ghent University
1492
     *
1493
     * @version January 2007
1494
     */
1495
    public static function delete_all_survey_questions($survey_id, $shared = false)
1496
    {
1497
        $course_id = api_get_course_int_id();
1498
        $survey_id = (int) $survey_id;
1499
1500
        // Table definitions
1501
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1502
        $course_condition = " c_id = $course_id AND ";
1503
        if ($shared) {
1504
            $course_condition = '';
1505
            $table_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1506
        }
1507
1508
        $sql = "DELETE FROM $table_survey_question
1509
		        WHERE $course_condition survey_id = '".$survey_id."'";
1510
1511
        // Deleting the survey questions
1512
        Database::query($sql);
1513
1514
        // Deleting all the options of the questions of the survey
1515
        self::delete_all_survey_questions_options($survey_id, $shared);
1516
1517
        // Deleting all the answers on this survey
1518
        self::delete_all_survey_answers($survey_id);
1519
1520
        return true;
1521
    }
1522
1523
    /**
1524
     * This function deletes a survey question and all its options.
1525
     *
1526
     * @param int  $survey_id   the id of the survey
1527
     * @param int  $question_id the id of the question
1528
     * @param bool $shared
1529
     *
1530
     * @return mixed False on error, true if the question could be deleted
1531
     *
1532
     * @todo also delete the answers to this question
1533
     *
1534
     * @author Patrick Cool <[email protected]>, Ghent University
1535
     *
1536
     * @version March 2007
1537
     */
1538
    public static function delete_survey_question($survey_id, $question_id, $shared = false)
1539
    {
1540
        $survey_id = (int) $survey_id;
1541
        $question_id = (int) $question_id;
1542
        $course_id = api_get_course_int_id();
1543
1544
        if ($shared) {
1545
            self::delete_shared_survey_question($survey_id, $question_id);
1546
        }
1547
1548
        // Table definitions
1549
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1550
        // Deleting the survey questions
1551
        $sql = "DELETE FROM $table
1552
		        WHERE
1553
		            c_id = $course_id AND
1554
		            survey_id = $survey_id AND
1555
		            question_id = $question_id";
1556
        $result = Database::query($sql);
1557
        if (false == $result) {
1558
            return false;
1559
        }
1560
        // Deleting the options of the question of the survey
1561
        self::delete_survey_question_option($survey_id, $question_id, $shared);
1562
1563
        return true;
1564
    }
1565
1566
    /**
1567
     * This function deletes a shared survey question from the main database and all its options.
1568
     *
1569
     * @param int $question_id the id of the question
1570
     *
1571
     * @todo delete all the options of this question
1572
     *
1573
     * @author Patrick Cool <[email protected]>, Ghent University
1574
     *
1575
     * @version March 2007
1576
     */
1577
    public static function delete_shared_survey_question($survey_id, $question_id)
1578
    {
1579
        // Table definitions
1580
        $table_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1581
        $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1582
1583
        // First we have to get the shared_question_id
1584
        $question_data = self::get_question($question_id);
1585
1586
        // Deleting the survey questions
1587
        $sql = "DELETE FROM $table_survey_question
1588
		        WHERE question_id='".intval($question_data['shared_question_id'])."'";
1589
        Database::query($sql);
1590
1591
        // Deleting the options of the question of the survey question
1592
        $sql = "DELETE FROM $table_survey_question_option
1593
		        WHERE question_id='".intval($question_data['shared_question_id'])."'";
1594
        Database::query($sql);
1595
    }
1596
1597
    /**
1598
     * This function stores the options of the questions in the table.
1599
     *
1600
     * @param array $form_content
1601
     *
1602
     * @author Patrick Cool <[email protected]>, Ghent University
1603
     *
1604
     * @version January 2007
1605
     *
1606
     * @todo writing the update statement when editing a question
1607
     */
1608
    public static function save_question_options($form_content, $survey_data, $dataFromDatabase = [])
1609
    {
1610
        $course_id = api_get_course_int_id();
1611
        $type = $form_content['type'];
1612
1613
        // A percentage question type has options 1 -> 100
1614
        if ('percentage' === $type) {
1615
            for ($i = 1; $i < 101; $i++) {
1616
                $form_content['answers'][] = $i;
1617
            }
1618
        }
1619
1620
        if (is_numeric($survey_data['survey_share']) && 0 != $survey_data['survey_share']) {
1621
            self::save_shared_question_options($form_content, $survey_data);
0 ignored issues
show
Bug Best Practice introduced by
The method SurveyManager::save_shared_question_options() is not static, but was called statically. ( Ignorable by Annotation )

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

1621
            self::/** @scrutinizer ignore-call */ 
1622
                  save_shared_question_options($form_content, $survey_data);
Loading history...
1622
        }
1623
1624
        // Table definition
1625
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1626
1627
        // We are editing a question so we first have to remove all the existing options from the database
1628
        $optionsToDelete = [];
1629
        if (isset($dataFromDatabase['answer_data'])) {
1630
            foreach ($dataFromDatabase['answer_data'] as $data) {
1631
                if ('other' === $data['data'] && 'multiplechoiceother' === $type) {
1632
                    continue;
1633
                }
1634
1635
                if (!in_array($data['iid'], $form_content['answersid'])) {
1636
                    $optionsToDelete[] = $data['iid'];
1637
                }
1638
            }
1639
        }
1640
1641
        if (!empty($optionsToDelete)) {
1642
            foreach ($optionsToDelete as $iid) {
1643
                $iid = (int) $iid;
1644
                $sql = "DELETE FROM $table
1645
			            WHERE
1646
			                iid = $iid AND
1647
			                c_id = $course_id AND
1648
                            question_id = '".intval($form_content['question_id'])."'
1649
                            ";
1650
                Database::query($sql);
1651
            }
1652
        }
1653
1654
        $counter = 1;
1655
        if (isset($form_content['answers']) && is_array($form_content['answers'])) {
1656
            for ($i = 0; $i < count($form_content['answers']); $i++) {
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...
1657
                $values = isset($form_content['values']) ? $form_content['values'][$i] : '';
1658
                $answerId = 0;
1659
                if (isset($form_content['answersid']) && isset($form_content['answersid'][$i])) {
1660
                    $answerId = $form_content['answersid'][$i];
1661
                }
1662
                if (empty($answerId)) {
1663
                    $params = [
1664
                        'c_id' => $course_id,
1665
                        'question_id' => $form_content['question_id'],
1666
                        'survey_id' => $form_content['survey_id'],
1667
                        'option_text' => $form_content['answers'][$i],
1668
                        'value' => $values,
1669
                        'sort' => $counter,
1670
                    ];
1671
                    $insertId = Database::insert($table, $params);
1672
                    if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1673
                        $sql = "UPDATE $table
1674
                                SET question_option_id = $insertId
1675
                                WHERE iid = $insertId";
1676
                        Database::query($sql);
1677
                        $counter++;
1678
                    }
1679
                } else {
1680
                    $params = [
1681
                        'option_text' => $form_content['answers'][$i],
1682
                        'value' => $values,
1683
                        'sort' => $counter,
1684
                    ];
1685
                    Database::update($table, $params, ['iid = ?' => [$answerId]]);
1686
                    $counter++;
1687
                }
1688
            }
1689
        }
1690
1691
        if ('multiplechoiceother' === $type) {
1692
            // First time creation
1693
            if (empty($dataFromDatabase['answer_data'])) {
1694
                $params = [
1695
                    'c_id' => $course_id,
1696
                    'question_id' => $form_content['question_id'],
1697
                    'survey_id' => $form_content['survey_id'],
1698
                    'option_text' => 'other',
1699
                    'value' => 0,
1700
                    'sort' => $counter,
1701
                ];
1702
                $insertId = Database::insert($table, $params);
1703
                if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1704
                    $sql = "UPDATE $table
1705
                            SET question_option_id = $insertId
1706
                            WHERE iid = $insertId";
1707
                    Database::query($sql);
1708
                }
1709
            } else {
1710
                $params = [
1711
                    'option_text' => 'other',
1712
                    'value' => 0,
1713
                    'sort' => $counter,
1714
                ];
1715
                Database::update(
1716
                    $table,
1717
                    $params,
1718
                    [
1719
                        'c_id = ? AND question_id = ? AND survey_id = ? AND option_text = ?' => [
1720
                            $course_id,
1721
                            $form_content['question_id'],
1722
                            $form_content['survey_id'],
1723
                            'other',
1724
                        ],
1725
                    ]
1726
                );
1727
            }
1728
        }
1729
    }
1730
1731
    /**
1732
     * This function stores the options of the questions in the shared table.
1733
     *
1734
     * @param array $form_content
1735
     *
1736
     * @author Patrick Cool <[email protected]>, Ghent University
1737
     *
1738
     * @version February 2007
1739
     *
1740
     * @todo writing the update statement when editing a question
1741
     */
1742
    public function save_shared_question_options($form_content, $survey_data)
1743
    {
1744
        if (is_array($form_content) && is_array($form_content['answers'])) {
1745
            // Table definition
1746
            $table = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1747
1748
            // We are editing a question so we first have to remove all the existing options from the database
1749
            $sql = "DELETE FROM $table
1750
                    WHERE question_id = '".Database::escape_string($form_content['shared_question_id'])."'";
1751
            Database::query($sql);
1752
1753
            $counter = 1;
1754
            foreach ($form_content['answers'] as &$answer) {
1755
                $params = [
1756
                    'question_id' => $form_content['shared_question_id'],
1757
                    'survey_id' => $survey_data['is_shared'],
1758
                    'option_text' => $answer,
1759
                    'sort' => $counter,
1760
                ];
1761
                Database::insert($table, $params);
1762
1763
                $counter++;
1764
            }
1765
        }
1766
    }
1767
1768
    /**
1769
     * This function deletes all the options of the questions of a given survey
1770
     * This function is normally only called when a survey is deleted.
1771
     *
1772
     * @param int $survey_id the id of the survey that has to be deleted
1773
     *
1774
     * @return true
1775
     *
1776
     * @author Patrick Cool <[email protected]>, Ghent University
1777
     *
1778
     * @version January 2007
1779
     */
1780
    public static function delete_all_survey_questions_options($survey_id, $shared = false)
1781
    {
1782
        // Table definitions
1783
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1784
        $course_id = api_get_course_int_id();
1785
        $course_condition = " c_id = $course_id AND ";
1786
        if ($shared) {
1787
            $course_condition = '';
1788
            $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1789
        }
1790
1791
        $sql = "DELETE FROM $table_survey_question_option
1792
                WHERE $course_condition survey_id='".intval($survey_id)."'";
1793
1794
        // Deleting the options of the survey questions
1795
        Database::query($sql);
1796
1797
        return true;
1798
    }
1799
1800
    /**
1801
     * This function deletes the options of a given question.
1802
     *
1803
     * @param int  $survey_id
1804
     * @param int  $question_id
1805
     * @param bool $shared
1806
     *
1807
     * @return bool
1808
     *
1809
     * @author Patrick Cool <[email protected]>, Ghent University
1810
     * @author Julio Montoya
1811
     *
1812
     * @version March 2007
1813
     */
1814
    public static function delete_survey_question_option(
1815
        $survey_id,
1816
        $question_id,
1817
        $shared = false
1818
    ) {
1819
        $course_id = api_get_course_int_id();
1820
        $course_condition = " c_id = $course_id AND ";
1821
1822
        // Table definitions
1823
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1824
        if ($shared) {
1825
            $course_condition = '';
1826
            $table = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1827
        }
1828
1829
        // Deleting the options of the survey questions
1830
        $sql = "DELETE FROM $table
1831
		        WHERE
1832
		            $course_condition survey_id='".intval($survey_id)."' AND
1833
		            question_id='".intval($question_id)."'";
1834
        Database::query($sql);
1835
1836
        return true;
1837
    }
1838
1839
    /**
1840
     * SURVEY ANSWERS FUNCTIONS.
1841
     */
1842
1843
    /**
1844
     * This function deletes all the answers anyone has given on this survey
1845
     * This function is normally only called when a survey is deleted.
1846
     *
1847
     * @param $survey_id the id of the survey that has to be deleted
1848
     *
1849
     * @return true
1850
     *
1851
     * @todo write the function
1852
     *
1853
     * @author Patrick Cool <[email protected]>, Ghent University
1854
     *
1855
     * @version January 2007,december 2008
1856
     */
1857
    public static function delete_all_survey_answers($survey_id)
1858
    {
1859
        $course_id = api_get_course_int_id();
1860
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1861
        $survey_id = (int) $survey_id;
1862
        $sql = "DELETE FROM $table
1863
                WHERE c_id = $course_id AND survey_id = $survey_id";
1864
        Database::query($sql);
1865
1866
        return true;
1867
    }
1868
1869
    /**
1870
     * @param int $user_id
1871
     * @param int $survey_id
1872
     * @param int $course_id
1873
     *
1874
     * @return bool
1875
     */
1876
    public static function is_user_filled_survey($user_id, $survey_id, $course_id)
1877
    {
1878
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1879
        $user_id = (int) $user_id;
1880
        $course_id = (int) $course_id;
1881
        $survey_id = (int) $survey_id;
1882
1883
        $sql = "SELECT DISTINCT user
1884
                FROM $table
1885
                WHERE
1886
                    c_id		= $course_id AND
1887
                    user		= $user_id AND
1888
                    survey_id	= $survey_id";
1889
        $result = Database::query($sql);
1890
        if (Database::num_rows($result)) {
1891
            return true;
1892
        }
1893
1894
        return false;
1895
    }
1896
1897
    /**
1898
     * This function gets all the persons who have filled the survey.
1899
     *
1900
     * @param int $survey_id
1901
     *
1902
     * @return array
1903
     *
1904
     * @author Patrick Cool <[email protected]>, Ghent University
1905
     *
1906
     * @version February 2007
1907
     */
1908
    public static function get_people_who_filled_survey(
1909
        $survey_id,
1910
        $all_user_info = false,
1911
        $course_id = null
1912
    ) {
1913
        // Database table definition
1914
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1915
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1916
1917
        // Variable initialisation
1918
        $return = [];
1919
1920
        if (empty($course_id)) {
1921
            $course_id = api_get_course_int_id();
1922
        } else {
1923
            $course_id = (int) $course_id;
1924
        }
1925
1926
        $survey_id = (int) $survey_id;
1927
1928
        if ($all_user_info) {
1929
            $order_clause = api_sort_by_first_name()
1930
                ? ' ORDER BY user.firstname, user.lastname'
1931
                : ' ORDER BY user.lastname, user.firstname';
1932
            $sql = "SELECT DISTINCT
1933
			            answered_user.user as invited_user,
1934
			            user.firstname,
1935
			            user.lastname,
1936
			            user.id as user_id
1937
                    FROM $table_survey_answer answered_user
1938
                    LEFT JOIN $table_user as user ON answered_user.user = user.id
1939
                    WHERE
1940
                        answered_user.c_id = $course_id AND
1941
                        survey_id= '".$survey_id."' ".
1942
                $order_clause;
1943
        } else {
1944
            $sql = "SELECT DISTINCT user FROM $table_survey_answer
1945
			        WHERE c_id = $course_id AND survey_id= '".$survey_id."'  ";
1946
1947
            if (api_get_configuration_value('survey_anonymous_show_answered')) {
1948
                $tblInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
1949
                $tblSurvey = Database::get_course_table(TABLE_SURVEY);
1950
1951
                $sql = "SELECT i.user FROM $tblInvitation i
1952
                    INNER JOIN $tblSurvey s
1953
                    ON i.survey_code = s.code
1954
                        AND i.c_id = s.c_id
1955
                        AND i.session_id = s.session_id
1956
                    WHERE i.answered IS TRUE AND s.iid = $survey_id";
1957
            }
1958
        }
1959
1960
        $res = Database::query($sql);
1961
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1962
            if ($all_user_info) {
1963
                $userInfo = api_get_user_info($row['user_id']);
1964
                $row['user_info'] = $userInfo;
1965
                $return[] = $row;
1966
            } else {
1967
                $return[] = $row['user'];
1968
            }
1969
        }
1970
1971
        return $return;
1972
    }
1973
1974
    /**
1975
     * @return bool
1976
     */
1977
    public static function survey_generation_hash_available()
1978
    {
1979
        if (extension_loaded('mcrypt')) {
1980
            return true;
1981
        }
1982
1983
        return false;
1984
    }
1985
1986
    /**
1987
     * @param int $survey_id
1988
     * @param int $course_id
1989
     * @param int $session_id
1990
     * @param int $group_id
1991
     *
1992
     * @return string
1993
     */
1994
    public static function generate_survey_hash($survey_id, $course_id, $session_id, $group_id)
1995
    {
1996
        return hash('sha512', api_get_security_key().'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id);
1997
    }
1998
1999
    /**
2000
     * @param int    $survey_id
2001
     * @param int    $course_id
2002
     * @param int    $session_id
2003
     * @param int    $group_id
2004
     * @param string $hash
2005
     *
2006
     * @return bool
2007
     */
2008
    public static function validate_survey_hash($survey_id, $course_id, $session_id, $group_id, $hash)
2009
    {
2010
        $generatedHash = self::generate_survey_hash($survey_id, $course_id, $session_id, $group_id);
2011
        if ($generatedHash == $hash) {
2012
            return true;
2013
        }
2014
2015
        return false;
2016
    }
2017
2018
    /**
2019
     * @param int $survey_id
2020
     * @param int $course_id
2021
     * @param int $session_id
2022
     * @param int $group_id
2023
     *
2024
     * @return string
2025
     */
2026
    public static function generate_survey_link(
2027
        $survey_id,
2028
        $course_id,
2029
        $session_id,
2030
        $group_id
2031
    ) {
2032
        $code = self::generate_survey_hash(
2033
            $survey_id,
2034
            $course_id,
2035
            $session_id,
2036
            $group_id
2037
        );
2038
2039
        return api_get_path(WEB_CODE_PATH).'survey/link.php?h='.$code.'&i='.$survey_id.'&c='.intval($course_id).'&s='
2040
            .intval($session_id).'&g='.$group_id;
2041
    }
2042
2043
    /**
2044
     * Check if the current user has mandatory surveys no-answered
2045
     * and redirect to fill the first found survey.
2046
     */
2047
    public static function protectByMandatory()
2048
    {
2049
        if (false !== strpos($_SERVER['SCRIPT_NAME'], 'fillsurvey.php')) {
2050
            return;
2051
        }
2052
2053
        $userId = api_get_user_id();
2054
        $courseId = api_get_course_int_id();
2055
        $sessionId = api_get_session_id();
2056
2057
        if (!$userId) {
2058
            return;
2059
        }
2060
2061
        if (!$courseId) {
2062
            return;
2063
        }
2064
2065
        try {
2066
            /** @var CSurveyInvitation $invitation */
2067
            $invitation = Database::getManager()
2068
                ->createQuery("
2069
                    SELECT i FROM ChamiloCourseBundle:CSurveyInvitation i
2070
                    INNER JOIN ChamiloCourseBundle:CSurvey s
2071
                        WITH (s.code = i.surveyCode AND s.cId = i.cId AND s.sessionId = i.sessionId)
2072
                    INNER JOIN ChamiloCoreBundle:ExtraFieldValues efv WITH efv.itemId = s.iid
2073
                    INNER JOIN ChamiloCoreBundle:ExtraField ef WITH efv.field = ef.id
2074
                    WHERE
2075
                        i.answered = 0 AND
2076
                        i.cId = :course AND
2077
                        i.user = :user AND
2078
                        i.sessionId = :session AND
2079
                        :now BETWEEN s.availFrom AND s.availTill AND
2080
                        ef.variable = :variable AND
2081
                        efv.value = 1 AND
2082
                        s.surveyType != 3
2083
                    ORDER BY s.availTill ASC
2084
                ")
2085
                ->setMaxResults(1)
2086
                ->setParameters([
2087
                    'course' => $courseId,
2088
                    'user' => $userId,
2089
                    'session' => $sessionId,
2090
                    'now' => new DateTime('UTC', new DateTimeZone('UTC')),
2091
                    'variable' => 'is_mandatory',
2092
                ])
2093
                ->getSingleResult();
2094
        } catch (Exception $e) {
2095
            $invitation = null;
2096
        }
2097
2098
        if (!$invitation) {
2099
            return;
2100
        }
2101
2102
        Display::addFlash(
2103
            Display::return_message(get_lang('MandatorySurveyNoAnswered'), 'warning')
2104
        );
2105
2106
        $url = SurveyUtil::generateFillSurveyLink(
2107
            $invitation->getInvitationCode(),
2108
            api_get_course_info(),
2109
            api_get_session_id()
2110
        );
2111
2112
        header('Location: '.$url);
2113
        exit;
2114
    }
2115
2116
    /**
2117
     * This function empty surveys (invitations and answers).
2118
     *
2119
     * @param int $surveyId id of the survey to empty
2120
     *
2121
     * @return bool
2122
     */
2123
    public static function emptySurveyFromId($surveyId)
2124
    {
2125
        // Database table definitions
2126
        $surveyInvitationTable = Database:: get_course_table(TABLE_SURVEY_INVITATION);
2127
        $surveyAnswerTable = Database:: get_course_table(TABLE_SURVEY_ANSWER);
2128
        $surveyTable = Database:: get_course_table(TABLE_SURVEY);
2129
        $surveyId = (int) $surveyId;
2130
        $surveyData = self::get_survey($surveyId);
2131
        if (empty($surveyData)) {
2132
            return false;
2133
        }
2134
2135
        $surveyCode = $surveyData['survey_code'];
2136
        $courseId = (int) $surveyData['c_id'];
2137
        $sessionId = (int) $surveyData['session_id'];
2138
2139
        $sql = "DELETE FROM $surveyInvitationTable
2140
                WHERE session_id = $sessionId AND c_id = $courseId AND survey_code = '$surveyCode' ";
2141
        Database::query($sql);
2142
2143
        $sql = "DELETE FROM $surveyAnswerTable
2144
               WHERE survey_id = $surveyId AND c_id = $courseId ";
2145
        Database::query($sql);
2146
2147
        $sql = "UPDATE $surveyTable
2148
                SET invited = 0, answered = 0
2149
                WHERE survey_id = $surveyId AND c_id = $courseId AND session_id = $sessionId ";
2150
        Database::query($sql);
2151
2152
        return true;
2153
    }
2154
2155
    /**
2156
     * Copy survey specifying course ID and session ID where will be copied.
2157
     *
2158
     * @param int $surveyId
2159
     * @param int $targetCourseId  target course id
2160
     * @param int $targetSessionId target session id
2161
     *
2162
     * @return bool|int when fails or return the new survey id
2163
     */
2164
    public static function copySurveySession(
2165
        $surveyId,
2166
        $targetCourseId,
2167
        $targetSessionId
2168
    ) {
2169
        // Database table definitions
2170
        $surveyTable = Database::get_course_table(TABLE_SURVEY);
2171
        $surveyQuestionGroupTable = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
2172
        $surveyQuestionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
2173
        $surveyOptionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2174
        $surveyId = (int) $surveyId;
2175
        $targetCourseId = (int) $targetCourseId;
2176
        $targetSessionId = (int) $targetSessionId;
2177
2178
        $surveyData = self::get_survey($surveyId, 0, '', true);
2179
        if (empty($surveyData) || empty($targetCourseId)) {
2180
            return false;
2181
        }
2182
2183
        $originalCourseId = $surveyData['c_id'];
2184
        $originalSessionId = $surveyData['session_id'];
2185
2186
        $surveyData['code'] = self::generate_unique_code($surveyData['code']);
2187
        $surveyData['c_id'] = $targetCourseId;
2188
        $surveyData['session_id'] = $targetSessionId;
2189
        // Add a "Copy" suffix if copied inside the same course
2190
        if ($targetCourseId == $originalCourseId) {
2191
            $surveyData['title'] = $surveyData['title'].' '.get_lang('Copy');
2192
        }
2193
        unset($surveyData['iid']);
2194
        unset($surveyData['id']);
2195
2196
        $newSurveyId = Database::insert($surveyTable, $surveyData);
2197
2198
        if ($newSurveyId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $newSurveyId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2199
            $sql = "UPDATE $surveyTable SET survey_id = $newSurveyId
2200
                    WHERE iid = $newSurveyId";
2201
            Database::query($sql);
2202
2203
            $sql = "SELECT * FROM $surveyQuestionGroupTable
2204
                    WHERE c_id = $originalCourseId AND survey_id = $surveyId";
2205
            $res = Database::query($sql);
2206
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2207
                $params = [
2208
                    'c_id' => $targetCourseId,
2209
                    'name' => $row['name'],
2210
                    'description' => $row['description'],
2211
                    'survey_id' => $newSurveyId,
2212
                ];
2213
                $insertId = Database::insert($surveyQuestionGroupTable, $params);
2214
                if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2215
                    $sql = "UPDATE $surveyQuestionGroupTable SET id = iid WHERE iid = $insertId";
2216
                    Database::query($sql);
2217
                    $group_id[$row['id']] = $insertId;
2218
                }
2219
            }
2220
2221
            // Get questions
2222
            $sql = "SELECT * FROM $surveyQuestionTable
2223
                    WHERE c_id = $originalCourseId AND survey_id = $surveyId";
2224
            $res = Database::query($sql);
2225
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2226
                $params = [
2227
                    'c_id' => $targetCourseId,
2228
                    'survey_id' => $newSurveyId,
2229
                    'survey_question' => $row['survey_question'],
2230
                    'survey_question_comment' => $row['survey_question_comment'],
2231
                    'type' => $row['type'],
2232
                    'display' => $row['display'],
2233
                    'sort' => $row['sort'],
2234
                    'shared_question_id' => $row['shared_question_id'],
2235
                    'max_value' => $row['max_value'],
2236
                    'survey_group_pri' => $row['survey_group_pri'],
2237
                    'survey_group_sec1' => $row['survey_group_sec1'],
2238
                    'survey_group_sec2' => $row['survey_group_sec2'],
2239
                ];
2240
2241
                if (api_get_configuration_value('allow_required_survey_questions')) {
2242
                    if (isset($row['is_required'])) {
2243
                        $params['is_required'] = $row['is_required'];
2244
                    }
2245
                }
2246
2247
                $insertId = Database::insert($surveyQuestionTable, $params);
2248
                if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2249
                    $sql = "UPDATE $surveyQuestionTable
2250
                            SET question_id = iid
2251
                            WHERE iid = $insertId";
2252
                    Database::query($sql);
2253
2254
                    $question_id[$row['question_id']] = $insertId;
2255
                }
2256
            }
2257
2258
            // Get questions options
2259
            $sql = "SELECT * FROM $surveyOptionsTable
2260
                    WHERE survey_id = $surveyId AND c_id = $originalCourseId";
2261
2262
            $res = Database::query($sql);
2263
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2264
                $params = [
2265
                    'c_id' => $targetCourseId,
2266
                    'question_id' => $question_id[$row['question_id']],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $question_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
2267
                    'survey_id' => $newSurveyId,
2268
                    'option_text' => $row['option_text'],
2269
                    'sort' => $row['sort'],
2270
                    'value' => $row['value'],
2271
                ];
2272
                $insertId = Database::insert($surveyOptionsTable, $params);
2273
                if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2274
                    $sql = "UPDATE $surveyOptionsTable SET question_option_id = $insertId WHERE iid = $insertId";
2275
                    Database::query($sql);
2276
                }
2277
            }
2278
2279
            return $newSurveyId;
2280
        }
2281
2282
        return false;
2283
    }
2284
2285
    /**
2286
     * Copy/duplicate one question (into the same survey).
2287
     * Note: Relies on the question iid to find all necessary info.
2288
     *
2289
     * @param int $questionId
2290
     *
2291
     * @return int The new question's iid, or 0 on error
2292
     */
2293
    public static function copyQuestion($questionId)
2294
    {
2295
        if (empty($questionId)) {
2296
            return 0;
2297
        }
2298
        $questionId = (int) $questionId;
2299
        $questionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
2300
        $optionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2301
2302
        // Get questions
2303
        $sql = "SELECT * FROM $questionTable WHERE iid = $questionId";
2304
        $res = Database::query($sql);
2305
        if (false == $res) {
2306
            // Could not find this question
2307
            return 0;
2308
        }
2309
        $row = Database::fetch_array($res, 'ASSOC');
2310
        $params = [
2311
            'c_id' => $row['c_id'],
2312
            'survey_id' => $row['survey_id'],
2313
            'survey_question' => trim($row['survey_question']),
2314
            'survey_question_comment' => $row['survey_question_comment'],
2315
            'type' => $row['type'],
2316
            'display' => $row['display'],
2317
            'shared_question_id' => $row['shared_question_id'],
2318
            'max_value' => $row['max_value'],
2319
            'survey_group_pri' => $row['survey_group_pri'],
2320
            'survey_group_sec1' => $row['survey_group_sec1'],
2321
            'survey_group_sec2' => $row['survey_group_sec2'],
2322
        ];
2323
        if (api_get_configuration_value('allow_required_survey_questions')) {
2324
            if (isset($row['is_required'])) {
2325
                $params['is_required'] = $row['is_required'];
2326
            }
2327
        }
2328
        // Get question position
2329
        $sqlSort = "SELECT max(sort) as sort FROM $questionTable
2330
                    WHERE survey_id = ".$row['survey_id'];
2331
        $resSort = Database::query($sqlSort);
2332
        $rowSort = Database::fetch_assoc($resSort);
2333
        $params['sort'] = $rowSort['sort'] + 1;
2334
        // Insert the new question
2335
        $insertId = Database::insert($questionTable, $params);
2336
        if (false == $insertId) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $insertId of type false|integer against false; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
2337
            return 0;
2338
        }
2339
        // Normalize question_id with iid
2340
        $sql = "UPDATE $questionTable
2341
                SET question_id = iid
2342
                WHERE iid = $insertId";
2343
        Database::query($sql);
2344
2345
        // Get questions options
2346
        $sql = "SELECT * FROM $optionsTable WHERE question_id = $questionId";
2347
        $res = Database::query($sql);
2348
        while ($row = Database::fetch_assoc($res)) {
2349
            $params = [
2350
                'c_id' => $row['c_id'],
2351
                'question_id' => $insertId,
2352
                'survey_id' => $row['survey_id'],
2353
                'option_text' => $row['option_text'],
2354
                'sort' => $row['sort'],
2355
                'value' => $row['value'],
2356
            ];
2357
            $optionId = Database::insert($optionsTable, $params);
2358
            if ($optionId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $optionId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2359
                $sql = "UPDATE $optionsTable SET question_option_id = $optionId WHERE iid = $optionId";
2360
                Database::query($sql);
2361
            }
2362
        }
2363
2364
        return $insertId;
2365
    }
2366
2367
    /**
2368
     * @param array $surveyData
2369
     *
2370
     * @return bool
2371
     */
2372
    public static function removeMultiplicateQuestions($surveyData)
2373
    {
2374
        if (empty($surveyData)) {
2375
            return false;
2376
        }
2377
        $surveyId = $surveyData['survey_id'];
2378
        $courseId = $surveyData['c_id'];
2379
2380
        if (empty($surveyId) || empty($courseId)) {
2381
            return false;
2382
        }
2383
2384
        $questions = self::get_questions($surveyId);
2385
        foreach ($questions as $question) {
2386
            // Questions marked with "geneated" were created using the "multiplicate" feature.
2387
            if ($question['survey_question_comment'] === 'generated') {
2388
                self::delete_survey_question($surveyId, $question['question_id']);
2389
            }
2390
        }
2391
    }
2392
2393
    /**
2394
     * @param array  $surveyData
2395
     * @param string $type by_class or by_user
2396
     *
2397
     * @return bool
2398
     */
2399
    public static function multiplicateQuestions($surveyData, $type)
2400
    {
2401
        if (empty($surveyData)) {
2402
            return false;
2403
        }
2404
        $surveyId = $surveyData['survey_id'];
2405
        $courseId = $surveyData['c_id'];
2406
2407
        if (empty($surveyId) || empty($courseId)) {
2408
            return false;
2409
        }
2410
2411
        $questions = self::get_questions($surveyId);
2412
2413
        if (empty($questions)) {
2414
            return false;
2415
        }
2416
2417
        $extraFieldValue = new ExtraFieldValue('survey');
2418
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
2419
        $groupId = null;
2420
        if ($groupData && !empty($groupData['value'])) {
2421
            $groupId = (int) $groupData['value'];
2422
        }
2423
        switch ($type) {
2424
            case 'by_class':
2425
                if (null === $groupId) {
2426
                    $obj = new UserGroup();
2427
                    $options['where'] = [' usergroup.course_id = ? ' => $courseId];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.
Loading history...
2428
                    $classList = $obj->getUserGroupInCourse($options);
2429
                    $classToParse = [];
2430
                    foreach ($classList as $class) {
2431
                        $users = $obj->get_users_by_usergroup($class['id']);
2432
                        if (empty($users)) {
2433
                            continue;
2434
                        }
2435
                        $classToParse[] = [
2436
                            'name' => $class['name'],
2437
                            'users' => $users,
2438
                        ];
2439
                    }
2440
                    self::parseMultiplicateUserList($classToParse, $questions, $courseId, $surveyData, true);
2441
                } else {
2442
                    $groupInfo = GroupManager::get_group_properties($groupId);
2443
                    if (!empty($groupInfo)) {
2444
                        $users = GroupManager::getStudents($groupInfo['iid'], true);
2445
                        if (!empty($users)) {
2446
                            $users = array_column($users, 'id');
2447
                            self::parseMultiplicateUserList(
2448
                                [
2449
                                    [
2450
                                        'name' => $groupInfo['name'],
2451
                                        'users' => $users,
2452
                                    ],
2453
                                ],
2454
                                $questions,
2455
                                $courseId,
2456
                                $surveyData,
2457
                                false
2458
                            );
2459
                        }
2460
                    }
2461
                }
2462
                break;
2463
            case 'by_user':
2464
                if (null === $groupId) {
2465
                    $sessionId = api_get_session_id();
2466
                    $users = CourseManager:: get_student_list_from_course_code(
2467
                        api_get_course_id(),
2468
                        !empty($sessionId),
2469
                        $sessionId
2470
                    );
2471
                    if (!empty($users)) {
2472
                        $users = array_column($users, 'id');
2473
                        self::parseMultiplicateUserListPerUser(
2474
                            [
2475
                                [
2476
                                    'name' => '',
2477
                                    'users' => $users,
2478
                                ],
2479
                            ],
2480
                            $questions,
2481
                            $courseId,
2482
                            $surveyData,
2483
                            false
2484
                        );
2485
                    }
2486
                } else {
2487
                    $groupInfo = GroupManager::get_group_properties($groupId);
2488
                    if (!empty($groupInfo)) {
2489
                        $users = GroupManager::getStudents($groupInfo['iid'], true);
2490
                        if (!empty($users)) {
2491
                            $users = array_column($users, 'id');
2492
                            self::parseMultiplicateUserListPerUser(
2493
                                [
2494
                                    [
2495
                                        'name' => $groupInfo['name'],
2496
                                        'users' => $users,
2497
                                    ],
2498
                                ],
2499
                                $questions,
2500
                                $courseId,
2501
                                $surveyData,
2502
                                false
2503
                            );
2504
                        }
2505
                    }
2506
                }
2507
                break;
2508
        }
2509
2510
        return true;
2511
    }
2512
2513
    public static function parseMultiplicateUserList($itemList, $questions, $courseId, $surveyData, $addClassNewPage = false)
2514
    {
2515
        if (empty($itemList) || empty($questions)) {
2516
            return false;
2517
        }
2518
2519
        $surveyId = $surveyData['survey_id'];
2520
        $classTag = '{{class_name}}';
2521
        $studentTag = '{{student_full_name}}';
2522
        $classCounter = 0;
2523
        $newQuestionList = [];
2524
        foreach ($questions as $question) {
2525
            $newQuestionList[$question['sort']] = $question;
2526
        }
2527
        ksort($newQuestionList);
2528
2529
        $order = api_get_configuration_value('survey_duplicate_order_by_name');
2530
        foreach ($itemList as $class) {
2531
            $className = $class['name'];
2532
            $users = $class['users'];
2533
            $userInfoList = [];
2534
            foreach ($users as $userId) {
2535
                $userInfoList[] = api_get_user_info($userId);
2536
            }
2537
2538
            if ($order) {
2539
                usort(
2540
                    $userInfoList,
2541
                    function ($a, $b) {
2542
                        return $a['lastname'] > $b['lastname'];
2543
                    }
2544
                );
2545
            }
2546
2547
            foreach ($newQuestionList as $question) {
2548
                $text = $question['question'];
2549
                if (false !== strpos($text, $classTag)) {
2550
                    $replacedText = str_replace($classTag, $className, $text);
2551
                    $values = [
2552
                        'c_id' => $courseId,
2553
                        'question_comment' => 'generated',
2554
                        'type' => $question['type'],
2555
                        'display' => $question['horizontalvertical'],
2556
                        'horizontalvertical' => $question['horizontalvertical'],
2557
                        'question' => $replacedText,
2558
                        'survey_id' => $surveyId,
2559
                        'question_id' => 0,
2560
                        'shared_question_id' => 0,
2561
                        'answers' => $question['answers'] ?? null,
2562
                    ];
2563
                    self::save_question($surveyData, $values, false);
2564
                    $classCounter++;
2565
                    continue;
2566
                }
2567
2568
                foreach ($userInfoList as $userInfo) {
2569
                    if (false !== strpos($text, $studentTag)) {
2570
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
2571
                        $values = [
2572
                            'c_id' => $courseId,
2573
                            'question_comment' => 'generated',
2574
                            'type' => $question['type'],
2575
                            'display' => $question['horizontalvertical'],
2576
                            'maximum_score' => $question['maximum_score'],
2577
                            'question' => $replacedText,
2578
                            'survey_id' => $surveyId,
2579
                            'question_id' => 0,
2580
                            'shared_question_id' => 0,
2581
                        ];
2582
2583
                        $answers = [];
2584
                        if (!empty($question['answers'])) {
2585
                            foreach ($question['answers'] as $answer) {
2586
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
2587
                                $answers[] = $replacedText;
2588
                            }
2589
                        }
2590
                        $values['answers'] = $answers;
2591
                        self::save_question($surveyData, $values, false);
2592
                    }
2593
                }
2594
2595
                if ($addClassNewPage && $classCounter < count($itemList)) {
2596
                    self::addGeneratedNewPage($courseId, $surveyId, $surveyData);
2597
                }
2598
            }
2599
        }
2600
2601
        return true;
2602
    }
2603
2604
    public static function parseMultiplicateUserListPerUser(
2605
        $itemList,
2606
        $questions,
2607
        $courseId,
2608
        $surveyData,
2609
        $addClassNewPage = false
2610
    ) {
2611
        if (empty($itemList) || empty($questions)) {
2612
            return false;
2613
        }
2614
2615
        $surveyId = $surveyData['survey_id'];
2616
        $classTag = '{{class_name}}';
2617
        $studentTag = '{{student_full_name}}';
2618
        $classCounter = 0;
2619
        $newQuestionList = [];
2620
        foreach ($questions as $question) {
2621
            $newQuestionList[$question['sort']] = $question;
2622
        }
2623
        ksort($newQuestionList);
2624
2625
        $order = api_get_configuration_value('survey_duplicate_order_by_name');
2626
        foreach ($itemList as $class) {
2627
            $className = $class['name'];
2628
            $users = $class['users'];
2629
            $userInfoList = [];
2630
            foreach ($users as $userId) {
2631
                $userInfoList[] = api_get_user_info($userId);
2632
            }
2633
2634
            if ($order) {
2635
                usort(
2636
                    $userInfoList,
2637
                    function ($a, $b) {
2638
                        return $a['lastname'] > $b['lastname'];
2639
                    }
2640
                );
2641
            }
2642
2643
            foreach ($newQuestionList as $question) {
2644
                $text = $question['question'];
2645
                if (false === strpos($text, $studentTag)) {
2646
                    $values = [
2647
                        'c_id' => $courseId,
2648
                        'question_comment' => 'generated',
2649
                        'type' => $question['type'],
2650
                        'display' => $question['horizontalvertical'],
2651
                        'horizontalvertical' => $question['horizontalvertical'],
2652
                        'question' => $text,
2653
                        'survey_id' => $surveyId,
2654
                        'question_id' => 0,
2655
                        'shared_question_id' => 0,
2656
                        'answers' => $question['answers'] ?? null,
2657
                    ];
2658
                    self::save_question($surveyData, $values, false);
2659
                } else {
2660
                    break;
2661
                }
2662
            }
2663
2664
            self::addGeneratedNewPage($courseId, $surveyId, $surveyData);
2665
2666
            $counter = 0;
2667
            foreach ($userInfoList as $userInfo) {
2668
                foreach ($newQuestionList as $question) {
2669
                    $text = $question['question'];
2670
                    if (false !== strpos($text, $studentTag)) {
2671
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
2672
                        $values = [
2673
                            'c_id' => $courseId,
2674
                            'question_comment' => 'generated',
2675
                            'type' => $question['type'],
2676
                            'display' => $question['horizontalvertical'],
2677
                            'maximum_score' => $question['maximum_score'],
2678
                            'question' => $replacedText,
2679
                            'survey_id' => $surveyId,
2680
                            'question_id' => 0,
2681
                            'shared_question_id' => 0,
2682
                        ];
2683
2684
                        $answers = [];
2685
                        if (!empty($question['answers'])) {
2686
                            foreach ($question['answers'] as $answer) {
2687
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
2688
                                $answers[] = $replacedText;
2689
                            }
2690
                        }
2691
                        $values['answers'] = $answers;
2692
                        self::save_question($surveyData, $values, false);
2693
                    }
2694
                }
2695
                $counter++;
2696
                if ($counter < count($userInfoList)) {
2697
                    self::addGeneratedNewPage($courseId, $surveyId, $surveyData);
2698
                }
2699
            }
2700
        }
2701
2702
        return true;
2703
    }
2704
2705
    public static function addGeneratedNewPage($courseId, $surveyId, $surveyData)
2706
    {
2707
        // Add end page
2708
        $values = [
2709
            'c_id' => $courseId,
2710
            'question_comment' => 'generated',
2711
            'type' => 'pagebreak',
2712
            'display' => 'horizontal',
2713
            'question' => get_lang('QuestionForNextClass'),
2714
            'survey_id' => $surveyId,
2715
            'question_id' => 0,
2716
            'shared_question_id' => 0,
2717
        ];
2718
        self::save_question($surveyData, $values, false);
2719
    }
2720
2721
    public static function hasDependency($survey)
2722
    {
2723
        if (false === api_get_configuration_value('survey_question_dependency')) {
2724
            return false;
2725
        }
2726
2727
        if (empty($survey)) {
2728
            return false;
2729
        }
2730
2731
        if (!isset($survey['survey_id'])) {
2732
            return false;
2733
        }
2734
2735
        $courseId = (int) $survey['c_id'];
2736
        $surveyId = (int) $survey['survey_id'];
2737
2738
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
2739
2740
        $sql = "SELECT COUNT(iid) count FROM $table
2741
                WHERE
2742
                    c_id = $courseId AND
2743
                    survey_id = $surveyId AND
2744
                    parent_option_id <> 0
2745
                LIMIT 1
2746
                ";
2747
        $result = Database::query($sql);
2748
        $row = Database::fetch_array($result);
2749
2750
        if ($row) {
2751
            return $row['count'] > 0;
2752
        }
2753
2754
        return false;
2755
    }
2756
2757
    /**
2758
     * @param array $survey
2759
     *
2760
     * @return int
2761
     */
2762
    public static function getCountPages($survey)
2763
    {
2764
        if (empty($survey) || !isset($survey['iid'])) {
2765
            return 0;
2766
        }
2767
2768
        $courseId = (int) $survey['c_id'];
2769
        $surveyId = (int) $survey['survey_id'];
2770
2771
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
2772
2773
        // pagebreak
2774
        $sql = "SELECT COUNT(iid) FROM $table
2775
                WHERE
2776
                    survey_question NOT LIKE '%{{%' AND
2777
                    type = 'pagebreak' AND
2778
                    c_id = $courseId AND
2779
                    survey_id = $surveyId";
2780
        $result = Database::query($sql);
2781
        $numberPageBreaks = Database::result($result, 0, 0);
2782
2783
        // No pagebreak
2784
        $sql = "SELECT COUNT(iid) FROM $table
2785
                WHERE
2786
                    survey_question NOT LIKE '%{{%' AND
2787
                    type != 'pagebreak' AND
2788
                    c_id = $courseId AND
2789
                    survey_id = $surveyId";
2790
        $result = Database::query($sql);
2791
        $countOfQuestions = Database::result($result, 0, 0);
2792
2793
        if (1 == $survey['one_question_per_page']) {
2794
            if (!empty($countOfQuestions)) {
2795
                return $countOfQuestions;
2796
            }
2797
2798
            return 1;
2799
        }
2800
2801
        if (empty($numberPageBreaks)) {
2802
            return 1;
2803
        }
2804
2805
        return $numberPageBreaks + 1;
2806
    }
2807
2808
    /**
2809
     * Check whether this survey has ended. If so, display message and exit rhis script.
2810
     *
2811
     * @param array $surveyData Survey data
2812
     */
2813
    public static function checkTimeAvailability($surveyData)
2814
    {
2815
        if (empty($surveyData)) {
2816
            api_not_allowed(true);
2817
        }
2818
2819
        $allowSurveyAvailabilityDatetime = api_get_configuration_value('allow_survey_availability_datetime');
2820
        $utcZone = new DateTimeZone('UTC');
2821
        $startDate = new DateTime($surveyData['start_date'], $utcZone);
2822
        $endDate = new DateTime($surveyData['end_date'], $utcZone);
2823
        $currentDate = new DateTime('now', $utcZone);
2824
        if (!$allowSurveyAvailabilityDatetime) {
2825
            $currentDate->modify('today');
2826
        }
2827
        if ($currentDate < $startDate) {
2828
            api_not_allowed(
2829
                true,
2830
                Display:: return_message(
2831
                    get_lang('SurveyNotAvailableYet'),
2832
                    'warning',
2833
                    false
2834
                )
2835
            );
2836
        }
2837
2838
        if ($currentDate > $endDate) {
2839
            api_not_allowed(
2840
                true,
2841
                Display:: return_message(
2842
                    get_lang('SurveyNotAvailableAnymore'),
2843
                    'warning',
2844
                    false
2845
                )
2846
            );
2847
        }
2848
    }
2849
2850
    /**
2851
     * @param int    $userId
2852
     * @param string $surveyCode
2853
     * @param int    $courseId
2854
     * @param int    $sessionId
2855
     * @param int    $groupId
2856
     *
2857
     * @return array|CSurveyInvitation[]
2858
     */
2859
    public static function getUserInvitationsForSurveyInCourse(
2860
        $userId,
2861
        $surveyCode,
2862
        $courseId,
2863
        $sessionId = 0,
2864
        $groupId = 0
2865
    ) {
2866
        $invitationRepo = Database::getManager()->getRepository('ChamiloCourseBundle:CSurveyInvitation');
2867
2868
        return $invitationRepo->findBy(
2869
            [
2870
                'user' => $userId,
2871
                'cId' => $courseId,
2872
                'sessionId' => $sessionId,
2873
                'groupId' => $groupId,
2874
                'surveyCode' => $surveyCode,
2875
            ],
2876
            ['invitationDate' => 'DESC']
2877
        );
2878
    }
2879
2880
    /**
2881
     * @param array $userInfo
2882
     * @param int   $answered (1 = answered 0 = not answered)
2883
     *
2884
     * @return string
2885
     */
2886
    public static function surveyReport($userInfo, $answered = 0)
2887
    {
2888
        $userId = isset($userInfo['user_id']) ? (int) $userInfo['user_id'] : 0;
2889
        $answered = (int) $answered;
2890
2891
        if (empty($userId)) {
2892
            return '';
2893
        }
2894
2895
        $em = Database::getManager();
2896
        $repo = $em->getRepository('ChamiloCourseBundle:CSurveyInvitation');
2897
        $repoSurvey = $em->getRepository('ChamiloCourseBundle:CSurvey');
2898
        $invitations = $repo->findBy(['user' => $userId, 'answered' => $answered]);
2899
        $mainUrl = api_get_path(WEB_CODE_PATH).'survey/survey.php?';
2900
        $content = '';
2901
2902
        if (empty($answered)) {
2903
            $content .= Display::page_subheader(get_lang('Unanswered'));
2904
        } else {
2905
            $content .= Display::page_subheader(get_lang('Answered'));
2906
        }
2907
2908
        if (!empty($invitations)) {
2909
            $table = new HTML_Table(['class' => 'table']);
2910
            $table->setHeaderContents(0, 0, get_lang('SurveyName'));
2911
            $table->setHeaderContents(0, 1, get_lang('Course'));
2912
2913
            if (empty($answered)) {
2914
                $table->setHeaderContents(0, 2, get_lang('Survey').' - '.get_lang('EndDate'));
2915
            }
2916
2917
            // Not answered
2918
            /** @var CSurveyInvitation $invitation */
2919
            $row = 1;
2920
            foreach ($invitations as $invitation) {
2921
                $courseId = $invitation->getCId();
2922
                $courseInfo = api_get_course_info_by_id($courseId);
2923
2924
                $courseCode = $courseInfo['code'];
2925
                if (empty($courseInfo)) {
2926
                    continue;
2927
                }
2928
                $sessionId = $invitation->getSessionId();
2929
2930
                if (!empty($answered)) {
2931
                    // check if user is subscribed to the course/session
2932
                    if (empty($sessionId)) {
2933
                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode);
2934
                    } else {
2935
                        $subscribe = CourseManager::is_user_subscribed_in_course(
2936
                            $userId,
2937
                            $courseCode,
2938
                            true,
2939
                            $sessionId
2940
                        );
2941
                    }
2942
2943
                    // User is not subscribe skip!
2944
                    if (empty($subscribe)) {
2945
                        continue;
2946
                    }
2947
                }
2948
2949
                $surveyCode = $invitation->getSurveyCode();
2950
2951
                $survey = $repoSurvey->findOneBy([
2952
                    'cId' => $courseId,
2953
                    'sessionId' => $sessionId,
2954
                    'code' => $surveyCode,
2955
                ]);
2956
2957
                if (empty($survey)) {
2958
                    continue;
2959
                }
2960
2961
                $url = $mainUrl.'survey_id='.$survey->getSurveyId().'&cidReq='.$courseCode.'&id_session='.$sessionId;
2962
                $title = $survey->getTitle();
2963
                $title = Display::url($title, $url);
2964
2965
                if (!empty($sessionId)) {
2966
                    $sessionInfo = api_get_session_info($sessionId);
2967
                    $courseInfo['name'] .= ' ('.$sessionInfo['name'].')';
2968
                }
2969
2970
                $surveyData = self::get_survey($survey->getSurveyId(), 0, $courseCode);
2971
                $table->setCellContents($row, 0, $title);
2972
                $table->setCellContents($row, 1, $courseInfo['name']);
2973
2974
                if (empty($answered)) {
2975
                    $table->setHeaderContents(
2976
                        $row,
2977
                        2,
2978
                        api_get_local_time(
2979
                            $survey->getAvailTill(),
2980
                            null,
2981
                            null,
2982
                            true,
2983
                            false
2984
                        )
2985
                    );
2986
                }
2987
2988
                if (!empty($answered) && $surveyData['anonymous'] == 0) {
2989
                    $answers = SurveyUtil::displayCompleteReport(
2990
                        $surveyData,
2991
                        $userId,
2992
                        false,
2993
                        false,
2994
                        false
2995
                    );
2996
                    $table->setCellContents(++$row, 0, $answers);
2997
                    $table->setCellContents(++$row, 1, '');
2998
                }
2999
3000
                $row++;
3001
            }
3002
            $content .= $table->toHtml();
3003
        } else {
3004
            $content .= Display::return_message(get_lang('NoData'));
3005
        }
3006
3007
        return $content;
3008
    }
3009
3010
    public static function sendToTutors($surveyId)
3011
    {
3012
        $survey = Database::getManager()->getRepository('ChamiloCourseBundle:CSurvey')->find($surveyId);
3013
        if (null === $survey) {
3014
            return false;
3015
        }
3016
3017
        $extraFieldValue = new ExtraFieldValue('survey');
3018
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
3019
        if ($groupData && !empty($groupData['value'])) {
3020
            $groupInfo = GroupManager::get_group_properties($groupData['value']);
3021
            if ($groupInfo) {
3022
                $tutors = GroupManager::getTutors($groupInfo);
3023
                if (!empty($tutors)) {
3024
                    SurveyUtil::saveInviteMail(
3025
                        $survey,
3026
                        ' ',
3027
                        ' ',
3028
                        false
3029
                    );
3030
3031
                    foreach ($tutors as $tutor) {
3032
                        $subject = sprintf(get_lang('GroupSurveyX'), $groupInfo['name']);
3033
                        $content = sprintf(
3034
                            get_lang('HelloXGroupX'),
3035
                            $tutor['complete_name'],
3036
                            $groupInfo['name']
3037
                        );
3038
3039
                        SurveyUtil::saveInvitations(
3040
                            $surveyId,
3041
                            ['users' => $tutor['user_id']],
3042
                            $subject,
3043
                            $content,
3044
                            false,
3045
                            true,
3046
                            false,
3047
                            true
3048
                        );
3049
                    }
3050
                    Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false));
3051
                }
3052
                SurveyUtil::update_count_invited($survey->getCode());
3053
3054
                return true;
3055
            }
3056
        }
3057
3058
        return false;
3059
    }
3060
}
3061