Completed
Push — master ( 88715c...d7c14e )
by Julito
09:34
created

SurveyManager::copy_survey()   C

Complexity

Conditions 10
Paths 110

Size

Total Lines 120
Code Lines 85

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 85
nc 110
nop 3
dl 0
loc 120
rs 6.3939
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

322
                        $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...
323
                        if ($pos === false) {
324
                            $row['survey_version'] = $row['survey_version'] + 1;
325
                            $versionValue = $row['survey_version'];
326
                        } else {
327
                            $getlast = explode('\.', $row['survey_version']);
328
                            $lastversion = array_pop($getlast);
329
                            $lastversion = $lastversion + 1;
330
                            $add = implode('.', $getlast);
331
                            if ($add != '') {
332
                                $insertnewversion = $add.'.'.$lastversion;
333
                            } else {
334
                                $insertnewversion = $lastversion;
335
                            }
336
                            $versionValue = $insertnewversion;
337
                        }
338
                    }
339
                    $survey->setSurveyVersion($versionValue);
340
                }
341
            }
342
343
            $from = api_get_utc_datetime($values['start_date'].'00:00:00', true, true);
344
            $until = api_get_utc_datetime($values['end_date'].'23:59:59', true, true);
345
            if ($allowSurveyAvailabilityDatetime) {
346
                $from = api_get_utc_datetime($values['start_date'].':00', true, true);
347
                $until = api_get_utc_datetime($values['end_date'].':59', true, true);
348
            }
349
350
            $survey
351
                ->setCId($course_id)
352
                ->setCode(self::generateSurveyCode($values['survey_code']))
353
                ->setTitle($values['survey_title'])
354
                ->setSubtitle($values['survey_title'])
355
                ->setAuthor($_user['user_id'])
356
                ->setLang($values['survey_language'])
357
                ->setAvailFrom($from)
358
                ->setAvailTill($until)
359
                ->setIsShared($shared_survey_id)
360
                ->setTemplate('template')
361
                ->setIntro($values['survey_introduction'])
362
                ->setSurveyThanks($values['survey_thanks'])
363
                ->setAnonymous($values['anonymous'])
364
                ->setSessionId(api_get_session_id())
365
                ->setVisibleResults($values['visible_results'])
366
            ;
367
368
            $em = Database::getManager();
369
            $em->persist($survey);
370
            $em->flush();
371
372
            $survey_id = $survey->getIid();
373
            if ($survey_id > 0) {
374
                $sql = "UPDATE $table_survey SET survey_id = $survey_id
375
                        WHERE iid = $survey_id";
376
                Database::query($sql);
377
378
                // Insert into item_property
379
                api_item_property_update(
380
                    api_get_course_info(),
381
                    TOOL_SURVEY,
382
                    $survey_id,
383
                    'SurveyAdded',
384
                    api_get_user_id()
385
                );
386
            }
387
388
            if ($values['survey_type'] == 1 && !empty($values['parent_id'])) {
389
                self::copy_survey($values['parent_id'], $survey_id);
390
            }
391
392
            Display::addFlash(
393
                Display::return_message(
394
                    get_lang('SurveyCreatedSuccesfully'),
395
                    'success'
396
                )
397
            );
398
            $return['id'] = $survey_id;
399
        } else {
400
            // Check whether the code doesn't soon exists in this language
401
            $sql = 'SELECT 1 FROM '.$table_survey.'
402
			        WHERE
403
			            c_id = '.$course_id.' AND
404
			            code = "'.Database::escape_string($values['survey_code']).'" AND
405
			            lang = "'.Database::escape_string($values['survey_language']).'" AND
406
			            survey_id !='.intval($values['survey_id']);
407
            $rs = Database::query($sql);
408
            if (Database::num_rows($rs) > 0) {
409
                Display::addFlash(
410
                    Display::return_message(
411
                        get_lang('ThisSurveyCodeSoonExistsInThisLanguage'),
412
                        'error'
413
                    )
414
                );
415
                $return['type'] = 'error';
416
                $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0;
417
418
                return $return;
419
            }
420
421
            if (!isset($values['anonymous'])
422
                || (isset($values['anonymous']) && $values['anonymous'] == '')
423
            ) {
424
                $values['anonymous'] = 0;
425
            }
426
427
            $extraParams = [];
428
            $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : null;
429
            $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : null;
430
431
            if ($values['anonymous'] == 0) {
432
                $extraParams['show_form_profile'] = $values['show_form_profile'];
433
                if ($values['show_form_profile'] == 1) {
434
                    $fields = explode(',', $values['input_name_list']);
435
                    $field_values = '';
436
                    foreach ($fields as &$field) {
437
                        if ($field != '') {
438
                            if (!isset($values[$field]) ||
439
                                (isset($values[$field]) && $values[$field] == '')
440
                            ) {
441
                                $values[$field] = 0;
442
                            }
443
                            $field_values .= $field.':'.$values[$field].'@';
444
                        }
445
                    }
446
                    $extraParams['form_fields'] = $field_values;
447
                } else {
448
                    $extraParams['form_fields'] = '';
449
                }
450
            } else {
451
                $extraParams['show_form_profile'] = 0;
452
                $extraParams['form_fields'] = '';
453
            }
454
455
            $params = [
456
                'title' => $values['survey_title'],
457
                'subtitle' => $values['survey_subtitle'],
458
                'author' => $_user['user_id'],
459
                'lang' => $values['survey_language'],
460
                'avail_from' => $allowSurveyAvailabilityDatetime
461
                    ? api_get_utc_datetime($values['start_date'].':00')
462
                    : $values['start_date'],
463
                'avail_till' => $allowSurveyAvailabilityDatetime
464
                    ? api_get_utc_datetime($values['end_date'].':59')
465
                    : $values['end_date'],
466
                'is_shared' => $shared_survey_id,
467
                'template' => 'template',
468
                'intro' => $values['survey_introduction'],
469
                'surveythanks' => $values['survey_thanks'],
470
                'anonymous' => $values['anonymous'],
471
                'session_id' => api_get_session_id(),
472
                'visible_results' => $values['visible_results'],
473
            ];
474
475
            $params = array_merge($params, $extraParams);
476
            Database::update(
477
                $table_survey,
478
                $params,
479
                [
480
                    'c_id = ? AND survey_id = ?' => [
481
                        $course_id,
482
                        $values['survey_id'],
483
                    ],
484
                ]
485
            );
486
487
            // Update into item_property (update)
488
            api_item_property_update(
489
                api_get_course_info(),
490
                TOOL_SURVEY,
491
                $values['survey_id'],
492
                'SurveyUpdated',
493
                api_get_user_id()
494
            );
495
496
            Display::addFlash(
497
                Display::return_message(
498
                    get_lang('SurveyUpdatedSuccesfully'),
499
                    'confirmation'
500
                )
501
            );
502
503
            $return['id'] = $values['survey_id'];
504
        }
505
506
        $survey_id = intval($return['id']);
507
508
        // Gradebook
509
        $gradebook_option = false;
510
        if (isset($values['survey_qualify_gradebook'])) {
511
            $gradebook_option = $values['survey_qualify_gradebook'] > 0;
512
        }
513
514
        $gradebook_link_type = 8;
515
        $link_info = GradebookUtils::isResourceInCourseGradebook(
516
            $courseCode,
517
            $gradebook_link_type,
518
            $survey_id,
519
            $session_id
520
        );
521
522
        $gradebook_link_id = isset($link_info['id']) ? $link_info['id'] : false;
523
524
        if ($gradebook_option) {
525
            if ($survey_id > 0) {
526
                $title_gradebook = ''; // Not needed here.
527
                $description_gradebook = ''; // Not needed here.
528
                $survey_weight = floatval($_POST['survey_weight']);
529
                $max_score = 1;
530
531
                if (!$gradebook_link_id) {
532
                    GradebookUtils::add_resource_to_course_gradebook(
533
                        $values['category_id'],
534
                        $courseCode,
535
                        $gradebook_link_type,
536
                        $survey_id,
537
                        $title_gradebook,
538
                        $survey_weight,
539
                        $max_score,
540
                        $description_gradebook,
541
                        1,
542
                        $session_id
543
                    );
544
                } else {
545
                    GradebookUtils::updateResourceFromCourseGradebook(
546
                        $gradebook_link_id,
547
                        $courseCode,
548
                        $survey_weight
549
                    );
550
                }
551
            }
552
        } else {
553
            // Delete everything of the gradebook for this $linkId
554
            GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id);
555
        }
556
557
        return $return;
558
    }
559
560
    /**
561
     * This function stores a shared survey in the central database.
562
     *
563
     * @param array $values
564
     *
565
     * @return array $return the type of return message that has to be displayed and the message in it
566
     *
567
     * @author Patrick Cool <[email protected]>, Ghent University
568
     *
569
     * @version February 2007
570
     */
571
    public function store_shared_survey($values)
572
    {
573
        $_user = api_get_user_info();
574
        $_course = api_get_course_info();
575
576
        // Table definitions
577
        $table_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
578
579
        if (!$values['survey_id'] ||
580
            !is_numeric($values['survey_id']) ||
581
            $values['survey_share']['survey_share'] == 'true'
582
        ) {
583
            $sql = "INSERT INTO $table_survey (code, title, subtitle, author, lang, template, intro, surveythanks, creation_date, course_code) VALUES (
584
                    '".Database::escape_string($values['survey_code'])."',
585
                    '".Database::escape_string($values['survey_title'])."',
586
                    '".Database::escape_string($values['survey_subtitle'])."',
587
                    '".intval($_user['user_id'])."',
588
                    '".Database::escape_string($values['survey_language'])."',
589
                    '".Database::escape_string('template')."',
590
                    '".Database::escape_string($values['survey_introduction'])."',
591
                    '".Database::escape_string($values['survey_thanks'])."',
592
                    '".api_get_utc_datetime()."',
593
                    '".$_course['id']."')";
594
            Database::query($sql);
595
            $return = Database::insert_id();
596
597
            $sql = "UPDATE $table_survey SET survey_id = $return WHERE iid = $return";
598
            Database::query($sql);
599
        } else {
600
            $sql = "UPDATE $table_survey SET
601
                        code 			= '".Database::escape_string($values['survey_code'])."',
602
                        title 			= '".Database::escape_string($values['survey_title'])."',
603
                        subtitle 		= '".Database::escape_string($values['survey_subtitle'])."',
604
                        author 			= '".intval($_user['user_id'])."',
605
                        lang 			= '".Database::escape_string($values['survey_language'])."',
606
                        template 		= '".Database::escape_string('template')."',
607
                        intro			= '".Database::escape_string($values['survey_introduction'])."',
608
                        surveythanks	= '".Database::escape_string($values['survey_thanks'])."'
609
					WHERE survey_id = '".Database::escape_string($values['survey_share']['survey_share'])."'";
610
            Database::query($sql);
611
            $return = $values['survey_share']['survey_share'];
612
        }
613
614
        return $return;
615
    }
616
617
    /**
618
     * This function deletes a survey (and also all the question in that survey.
619
     *
620
     * @param int  $survey_id id of the survey that has to be deleted
621
     * @param bool $shared
622
     * @param int  $course_id
623
     *
624
     * @return true
625
     *
626
     * @author Patrick Cool <[email protected]>, Ghent University
627
     *
628
     * @version January 2007
629
     */
630
    public static function delete_survey($survey_id, $shared = false, $course_id = 0)
631
    {
632
        // Database table definitions
633
        if (empty($course_id)) {
634
            $course_id = api_get_course_int_id();
635
        }
636
637
        $survey_id = (int) $survey_id;
638
639
        if (empty($survey_id)) {
640
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
641
        }
642
643
        $course_info = api_get_course_info_by_id($course_id);
644
        $course_id = $course_info['real_id'];
645
646
        $table_survey = Database::get_course_table(TABLE_SURVEY);
647
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
648
649
        if ($shared) {
650
            $table_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
651
            // Deleting the survey
652
            $sql = "DELETE FROM $table_survey
653
                    WHERE survey_id='".$survey_id."'";
654
            Database::query($sql);
655
        } else {
656
            $sql = "DELETE FROM $table_survey
657
                    WHERE c_id = $course_id AND survey_id='".$survey_id."'";
658
            Database::query($sql);
659
        }
660
661
        // Deleting groups of this survey
662
        $sql = "DELETE FROM $table_survey_question_group
663
                WHERE c_id = $course_id AND survey_id='".$survey_id."'";
664
        Database::query($sql);
665
666
        // Deleting the questions of the survey
667
        self::delete_all_survey_questions($survey_id, $shared);
668
669
        // Update into item_property (delete)
670
        api_item_property_update(
671
            $course_info,
672
            TOOL_SURVEY,
673
            $survey_id,
674
            'SurveyDeleted',
675
            api_get_user_id()
676
        );
677
678
        Skill::deleteSkillsFromItem($survey_id, ITEM_TYPE_SURVEY);
679
680
        return true;
681
    }
682
683
    /**
684
     * @param int $survey_id
685
     * @param int $new_survey_id
686
     * @param int $targetCourseId
687
     *
688
     * @return bool
689
     */
690
    public static function copy_survey(
691
        $survey_id,
692
        $new_survey_id = null,
693
        $targetCourseId = null
694
    ) {
695
        $course_id = api_get_course_int_id();
696
        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...
697
            $targetCourseId = $course_id;
698
        }
699
700
        // Database table definitions
701
        $table_survey = Database::get_course_table(TABLE_SURVEY);
702
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
703
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
704
        $table_survey_options = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
705
        $survey_id = (int) $survey_id;
706
707
        // Get groups
708
        $survey_data = self::get_survey($survey_id, 0, null, true);
709
        if (empty($survey_data)) {
710
            return true;
711
        }
712
713
        if (empty($new_survey_id)) {
714
            $params = $survey_data;
715
            $params['code'] = self::generate_unique_code($params['code']);
716
            $params['c_id'] = $targetCourseId;
717
            unset($params['survey_id']);
718
            $params['session_id'] = api_get_session_id();
719
            $params['title'] = $params['title'].' '.get_lang('Copy');
720
            unset($params['iid']);
721
            $new_survey_id = Database::insert($table_survey, $params);
722
723
            if ($new_survey_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $new_survey_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...
724
                $sql = "UPDATE $table_survey SET survey_id = $new_survey_id
725
                        WHERE iid = $new_survey_id";
726
                Database::query($sql);
727
728
                // Insert into item_property
729
                api_item_property_update(
730
                    api_get_course_info(),
731
                    TOOL_SURVEY,
732
                    $new_survey_id,
733
                    'SurveyAdded',
734
                    api_get_user_id()
735
                );
736
            }
737
        } else {
738
            $new_survey_id = (int) $new_survey_id;
739
        }
740
741
        $sql = "SELECT * FROM $table_survey_question_group
742
                WHERE c_id = $course_id AND  survey_id='".$survey_id."'";
743
        $res = Database::query($sql);
744
        while ($row = Database::fetch_array($res, 'ASSOC')) {
745
            $params = [
746
                'c_id' => $targetCourseId,
747
                'name' => $row['name'],
748
                'description' => $row['description'],
749
                'survey_id' => $new_survey_id,
750
            ];
751
            $insertId = Database::insert($table_survey_question_group, $params);
752
753
            $sql = "UPDATE $table_survey_question_group SET id = iid
754
                    WHERE iid = $insertId";
755
            Database::query($sql);
756
757
            $group_id[$row['id']] = $insertId;
758
        }
759
760
        // Get questions
761
        $sql = "SELECT * FROM $table_survey_question
762
                WHERE c_id = $course_id AND survey_id='".$survey_id."'";
763
        $res = Database::query($sql);
764
        while ($row = Database::fetch_array($res, 'ASSOC')) {
765
            $params = [
766
                'c_id' => $targetCourseId,
767
                'survey_id' => $new_survey_id,
768
                'survey_question' => $row['survey_question'],
769
                'survey_question_comment' => $row['survey_question_comment'],
770
                'type' => $row['type'],
771
                'display' => $row['display'],
772
                'sort' => $row['sort'],
773
                'shared_question_id' => $row['shared_question_id'],
774
                'max_value' => $row['max_value'],
775
                'survey_group_pri' => $row['survey_group_pri'],
776
                'survey_group_sec1' => $row['survey_group_sec1'],
777
                'survey_group_sec2' => $row['survey_group_sec2'],
778
            ];
779
            $insertId = Database::insert($table_survey_question, $params);
780
            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...
781
                $sql = "UPDATE $table_survey_question SET question_id = iid WHERE iid = $insertId";
782
                Database::query($sql);
783
                $question_id[$row['question_id']] = $insertId;
784
            }
785
        }
786
787
        // Get questions options
788
        $sql = "SELECT * FROM $table_survey_options
789
                WHERE c_id = $course_id AND survey_id='".$survey_id."'";
790
791
        $res = Database::query($sql);
792
        while ($row = Database::fetch_array($res, 'ASSOC')) {
793
            $params = [
794
                'c_id' => $targetCourseId,
795
                '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...
796
                'survey_id' => $new_survey_id,
797
                'option_text' => $row['option_text'],
798
                'sort' => $row['sort'],
799
                'value' => $row['value'],
800
            ];
801
            $insertId = Database::insert($table_survey_options, $params);
802
            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...
803
                $sql = "UPDATE $table_survey_options SET question_option_id = $insertId
804
                        WHERE iid = $insertId";
805
                Database::query($sql);
806
            }
807
        }
808
809
        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...
810
    }
811
812
    /**
813
     * This function duplicates a survey (and also all the question in that survey.
814
     *
815
     * @param int $surveyId id of the survey that has to be duplicated
816
     * @param int $courseId id of the course which survey has to be duplicated
817
     *
818
     * @return true
819
     *
820
     * @author Eric Marguin <[email protected]>, Elixir Interactive
821
     *
822
     * @version October 2007
823
     */
824
    public static function empty_survey($surveyId, $courseId = 0)
825
    {
826
        // Database table definitions
827
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
828
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
829
        $table_survey = Database::get_course_table(TABLE_SURVEY);
830
831
        $courseId = (int) $courseId;
832
        $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
833
        $surveyId = (int) $surveyId;
834
835
        $datas = self::get_survey($surveyId);
836
        $session_where = '';
837
        if (api_get_session_id() != 0) {
838
            $session_where = ' AND session_id = "'.api_get_session_id().'" ';
839
        }
840
841
        $sql = 'DELETE FROM '.$table_survey_invitation.'
842
		        WHERE
843
		            c_id = '.$courseId.' AND
844
		            survey_code = "'.Database::escape_string($datas['code']).'" '.$session_where.' ';
845
        Database::query($sql);
846
847
        $sql = 'DELETE FROM '.$table_survey_answer.'
848
		        WHERE c_id = '.$courseId.' AND survey_id='.$surveyId;
849
        Database::query($sql);
850
851
        $sql = 'UPDATE '.$table_survey.' SET invited=0, answered=0
852
		        WHERE c_id = '.$courseId.' AND survey_id='.$surveyId;
853
        Database::query($sql);
854
855
        return true;
856
    }
857
858
    /**
859
     * This function recalculates the number of people who have taken the survey (=filled at least one question).
860
     *
861
     * @param array  $survey_data
862
     * @param array  $user
863
     * @param string $survey_code
864
     *
865
     * @return bool
866
     *
867
     * @author Patrick Cool <[email protected]>, Ghent University
868
     *
869
     * @version February 2007
870
     */
871
    public static function update_survey_answered($survey_data, $user, $survey_code)
872
    {
873
        // Database table definitions
874
        $table_survey = Database::get_course_table(TABLE_SURVEY);
875
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
876
877
        $survey_id = $survey_data['survey_id'];
878
        $course_id = $survey_data['c_id'];
879
        $session_id = $survey_data['session_id'];
880
881
        // Getting a list with all the people who have filled the survey
882
        $people_filled = self::get_people_who_filled_survey($survey_id, false, $course_id);
883
884
        $number = count($people_filled);
885
886
        // Storing this value in the survey table
887
        $sql = "UPDATE $table_survey
888
		        SET answered = $number
889
		        WHERE
890
                    c_id = $course_id AND
891
		            survey_id = ".intval($survey_id);
892
        Database::query($sql);
893
894
        $allow = api_get_configuration_value('survey_answered_at_field');
895
        // Requires DB change:
896
        // ALTER TABLE c_survey_invitation ADD answered_at DATETIME DEFAULT NULL;
897
        $answeredAt = '';
898
        if ($allow) {
899
            $answeredAt = "answered_at = '".api_get_utc_datetime()."',";
900
        }
901
902
        // Storing that the user has finished the survey.
903
        $sql = "UPDATE $table_survey_invitation
904
                SET $answeredAt answered = 1
905
                WHERE
906
                    c_id = $course_id AND
907
                    session_id = $session_id AND
908
                    user ='".Database::escape_string($user)."' AND
909
                    survey_code='".Database::escape_string($survey_code)."'";
910
        Database::query($sql);
911
    }
912
913
    /**
914
     * This function return the "icon" of the question type.
915
     *
916
     * @param string $type
917
     *
918
     * @author Patrick Cool <[email protected]>, Ghent University
919
     *
920
     * @version February 2007
921
     */
922
    public static function icon_question($type)
923
    {
924
        // the possible question types
925
        $possible_types = [
926
            'personality',
927
            'yesno',
928
            'multiplechoice',
929
            'multipleresponse',
930
            'open',
931
            'dropdown',
932
            'comment',
933
            'pagebreak',
934
            'percentage',
935
            'score',
936
        ];
937
938
        // the images array
939
        $icon_question = [
940
            'yesno' => 'yesno.png',
941
            'personality' => 'yesno.png',
942
            'multiplechoice' => 'mcua.png',
943
            'multipleresponse' => 'mcma.png',
944
            'open' => 'open_answer.png',
945
            'dropdown' => 'dropdown.png',
946
            'percentage' => 'percentagequestion.png',
947
            'score' => 'scorequestion.png',
948
            'comment' => 'commentquestion.png',
949
            'pagebreak' => 'page_end.png',
950
        ];
951
952
        if (in_array($type, $possible_types)) {
953
            return $icon_question[$type];
954
        } else {
955
            return false;
956
        }
957
    }
958
959
    /**
960
     * This function retrieves all the information of a question.
961
     *
962
     * @param int  $question_id the id of the question
963
     * @param bool $shared
964
     *
965
     * @return array
966
     *
967
     * @author Patrick Cool <[email protected]>, Ghent University
968
     *
969
     * @version January 2007
970
     *
971
     * @todo one sql call should do the trick
972
     */
973
    public static function get_question($question_id, $shared = false)
974
    {
975
        // Table definitions
976
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
977
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
978
        $course_id = api_get_course_int_id();
979
        $question_id = (int) $question_id;
980
981
        $sql = "SELECT * FROM $tbl_survey_question
982
                WHERE c_id = $course_id AND question_id='".$question_id."'
983
                ORDER BY `sort` ";
984
985
        $sqlOption = "  SELECT * FROM $table_survey_question_option
986
                        WHERE c_id = $course_id AND question_id='".$question_id."'
987
                        ORDER BY `sort` ";
988
989
        if ($shared) {
990
            $tbl_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
991
            $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
992
993
            $sql = "SELECT * FROM $tbl_survey_question
994
                    WHERE question_id='".$question_id."'
995
                    ORDER BY `sort` ";
996
            $sqlOption = "SELECT * FROM $table_survey_question_option
997
                          WHERE question_id='".$question_id."'
998
                          ORDER BY `sort` ";
999
        }
1000
1001
        // Getting the information of the question
1002
1003
        $result = Database::query($sql);
1004
        $row = Database::fetch_array($result, 'ASSOC');
1005
1006
        $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...
1007
        $return['question_id'] = $row['question_id'];
1008
        $return['type'] = $row['type'];
1009
        $return['question'] = $row['survey_question'];
1010
        $return['horizontalvertical'] = $row['display'];
1011
        $return['shared_question_id'] = $row['shared_question_id'];
1012
        $return['maximum_score'] = $row['max_value'];
1013
        $return['is_required'] = api_get_configuration_value('allow_required_survey_questions')
1014
            ? $row['is_required']
1015
            : false;
1016
1017
        if ($row['survey_group_pri'] != 0) {
1018
            $return['assigned'] = $row['survey_group_pri'];
1019
            $return['choose'] = 1;
1020
        } else {
1021
            $return['assigned1'] = $row['survey_group_sec1'];
1022
            $return['assigned2'] = $row['survey_group_sec2'];
1023
            $return['choose'] = 2;
1024
        }
1025
1026
        // Getting the information of the question options
1027
        $result = Database::query($sqlOption);
1028
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1029
            /** @todo this should be renamed to options instead of answers */
1030
            $return['answers'][] = $row['option_text'];
1031
            $return['values'][] = $row['value'];
1032
1033
            /** @todo this can be done more elegantly (used in reporting) */
1034
            $return['answersid'][] = $row['question_option_id'];
1035
        }
1036
1037
        return $return;
1038
    }
1039
1040
    /**
1041
     * This function gets all the question of any given survey.
1042
     *
1043
     * @param int $surveyId the id of the survey
1044
     * @param int $courseId
1045
     *
1046
     * @return array containing all the questions of the survey
1047
     *
1048
     * @author Patrick Cool <[email protected]>, Ghent University
1049
     *
1050
     * @version February 2007
1051
     *
1052
     * @todo one sql call should do the trick
1053
     */
1054
    public static function get_questions($surveyId, $courseId = 0)
1055
    {
1056
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1057
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1058
1059
        $courseId = (int) $courseId;
1060
        $surveyId = (int) $surveyId;
1061
1062
        if (empty($courseId)) {
1063
            $courseId = api_get_course_int_id();
1064
        }
1065
1066
        // Getting the information of the question
1067
        $sql = "SELECT * FROM $tbl_survey_question
1068
		        WHERE c_id = $courseId AND survey_id='".$surveyId."'";
1069
        $result = Database::query($sql);
1070
        $return = [];
1071
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1072
            $return[$row['question_id']]['survey_id'] = $row['survey_id'];
1073
            $return[$row['question_id']]['question_id'] = $row['question_id'];
1074
            $return[$row['question_id']]['type'] = $row['type'];
1075
            $return[$row['question_id']]['question'] = $row['survey_question'];
1076
            $return[$row['question_id']]['horizontalvertical'] = $row['display'];
1077
            $return[$row['question_id']]['maximum_score'] = $row['max_value'];
1078
            $return[$row['question_id']]['sort'] = $row['sort'];
1079
            $return[$row['question_id']]['survey_question_comment'] = $row['survey_question_comment'];
1080
        }
1081
1082
        // Getting the information of the question options
1083
        $sql = "SELECT * FROM $table_survey_question_option
1084
		        WHERE c_id = $courseId AND survey_id='".$surveyId."'";
1085
        $result = Database::query($sql);
1086
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1087
            $return[$row['question_id']]['answers'][] = $row['option_text'];
1088
        }
1089
1090
        return $return;
1091
    }
1092
1093
    /**
1094
     * This function saves a question in the database.
1095
     * This can be either an update of an existing survey or storing a new survey.
1096
     *
1097
     * @param array $survey_data
1098
     * @param array $form_content all the information of the form
1099
     *
1100
     * @return string
1101
     *
1102
     * @author Patrick Cool <[email protected]>, Ghent University
1103
     *
1104
     * @version January 2007
1105
     */
1106
    public static function save_question($survey_data, $form_content)
1107
    {
1108
        $return_message = '';
1109
        if (strlen($form_content['question']) > 1) {
1110
            // Checks length of the question
1111
            $empty_answer = false;
1112
1113
            if ($survey_data['survey_type'] == 1) {
1114
                if (empty($form_content['choose'])) {
1115
                    $return_message = 'PleaseChooseACondition';
1116
1117
                    return $return_message;
1118
                }
1119
1120
                if (($form_content['choose'] == 2) &&
1121
                    ($form_content['assigned1'] == $form_content['assigned2'])
1122
                ) {
1123
                    $return_message = 'ChooseDifferentCategories';
1124
1125
                    return $return_message;
1126
                }
1127
            }
1128
1129
            if ($form_content['type'] != 'percentage') {
1130
                if (isset($form_content['answers'])) {
1131
                    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...
1132
                        if (strlen($form_content['answers'][$i]) < 1) {
1133
                            $empty_answer = true;
1134
                            break;
1135
                        }
1136
                    }
1137
                }
1138
            }
1139
1140
            if ($form_content['type'] == 'score') {
1141
                if (strlen($form_content['maximum_score']) < 1) {
1142
                    $empty_answer = true;
1143
                }
1144
            }
1145
            $course_id = api_get_course_int_id();
1146
            if (!$empty_answer) {
1147
                // Table definitions
1148
                $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1149
1150
                // Getting all the information of the survey
1151
                $survey_data = self::get_survey($form_content['survey_id']);
1152
1153
                // Storing the question in the shared database
1154
                if (is_numeric($survey_data['survey_share']) && $survey_data['survey_share'] != 0) {
1155
                    $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

1155
                    /** @scrutinizer ignore-call */ 
1156
                    $shared_question_id = self::save_shared_question($form_content, $survey_data);
Loading history...
1156
                    $form_content['shared_question_id'] = $shared_question_id;
1157
                }
1158
1159
                // Storing a new question
1160
                if ($form_content['question_id'] == '' || !is_numeric($form_content['question_id'])) {
1161
                    // Finding the max sort order of the questions in the given survey
1162
                    $sql = "SELECT max(sort) AS max_sort
1163
					        FROM $tbl_survey_question
1164
                            WHERE c_id = $course_id AND survey_id='".intval($form_content['survey_id'])."'";
1165
                    $result = Database::query($sql);
1166
                    $row = Database::fetch_array($result, 'ASSOC');
1167
                    $max_sort = $row['max_sort'];
1168
1169
                    $question = new CSurveyQuestion();
1170
1171
                    // Some variables defined for survey-test type
1172
                    $extraParams = [];
1173
                    if (isset($_POST['choose'])) {
1174
                        if ($_POST['choose'] == 1) {
1175
                            $question->setSurveyGroupPri($_POST['assigned']);
1176
                        } elseif ($_POST['choose'] == 2) {
1177
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1178
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1179
                        }
1180
                    }
1181
1182
                    $question
1183
                        ->setSurveyQuestionComment($form_content['question_comment'] ?? '')
1184
                        ->setMaxValue($form_content['maximum_score'] ?? 0)
1185
                        ->setDisplay($form_content['horizontalvertical'] ?? '')
1186
                        ->setCId($course_id)
1187
                        ->setSurveyId($form_content['survey_id'])
1188
                        ->setSurveyQuestion($form_content['question'])
1189
                        ->setType($form_content['type'])
1190
                        ->setSort($max_sort + 1)
1191
                        ->setSharedQuestionId($form_content['shared_question_id'])
1192
                    ;
1193
1194
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1195
                        $question->setIsMandatory(isset($form_content['is_required']));
1196
                    }
1197
1198
                    $em = Database::getManager();
1199
                    $em->persist($question);
1200
                    $em->flush();
1201
1202
                    $question_id = $question->getIid();
1203
                    if ($question_id) {
1204
                        $sql = "UPDATE $tbl_survey_question SET question_id = $question_id
1205
                                WHERE iid = $question_id";
1206
                        Database::query($sql);
1207
1208
                        $form_content['question_id'] = $question_id;
1209
                        $return_message = 'QuestionAdded';
1210
                    }
1211
                } else {
1212
                    // Updating an existing question
1213
                    $extraParams = [];
1214
                    if (isset($_POST['choose'])) {
1215
                        if ($_POST['choose'] == 1) {
1216
                            $extraParams['survey_group_pri'] = $_POST['assigned'];
1217
                            $extraParams['survey_group_sec1'] = 0;
1218
                            $extraParams['survey_group_sec2'] = 0;
1219
                        } elseif ($_POST['choose'] == 2) {
1220
                            $extraParams['survey_group_pri'] = 0;
1221
                            $extraParams['survey_group_sec1'] = $_POST['assigned1'];
1222
                            $extraParams['survey_group_sec2'] = $_POST['assigned2'];
1223
                        }
1224
                    }
1225
1226
                    $maxScore = isset($form_content['maximum_score']) ? $form_content['maximum_score'] : null;
1227
                    $questionComment = isset($form_content['question_comment'])
1228
                        ? $form_content['question_comment']
1229
                        : null;
1230
1231
                    // Adding the question to the survey_question table
1232
                    $params = [
1233
                        'survey_question' => $form_content['question'],
1234
                        'survey_question_comment' => $questionComment,
1235
                        'display' => $form_content['horizontalvertical'],
1236
                    ];
1237
1238
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1239
                        $params['is_required'] = isset($form_content['is_required']);
1240
                    }
1241
1242
                    $params = array_merge($params, $extraParams);
1243
                    Database::update(
1244
                        $tbl_survey_question,
1245
                        $params,
1246
                        [
1247
                            'c_id = ? AND question_id = ?' => [
1248
                                $course_id,
1249
                                $form_content['question_id'],
1250
                            ],
1251
                        ]
1252
                    );
1253
                    $return_message = 'QuestionUpdated';
1254
                }
1255
1256
                if (!empty($form_content['survey_id'])) {
1257
                    //Updating survey
1258
                    api_item_property_update(
1259
                        api_get_course_info(),
1260
                        TOOL_SURVEY,
1261
                        $form_content['survey_id'],
1262
                        'SurveyUpdated',
1263
                        api_get_user_id()
1264
                    );
1265
                }
1266
1267
                // Storing the options of the question
1268
                self::save_question_options($form_content, $survey_data);
1269
            } else {
1270
                $return_message = 'PleasFillAllAnswer';
1271
            }
1272
        } else {
1273
            $return_message = 'PleaseEnterAQuestion';
1274
        }
1275
1276
        if (!empty($return_message)) {
1277
            Display::addFlash(Display::return_message(get_lang($return_message)));
1278
        }
1279
1280
        return $return_message;
1281
    }
1282
1283
    /**
1284
     * This function saves the question in the shared database.
1285
     *
1286
     * @param array $form_content all the information of the form
1287
     * @param array $survey_data  all the information of the survey
1288
     *
1289
     * @author Patrick Cool <[email protected]>, Ghent University
1290
     *
1291
     * @version February 2007
1292
     *
1293
     * @return int
1294
     *
1295
     * @todo editing of a shared question
1296
     */
1297
    public function save_shared_question($form_content, $survey_data)
1298
    {
1299
        $_course = api_get_course_info();
1300
1301
        // Table definitions
1302
        $tbl_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1303
1304
        // Storing a new question
1305
        if ($form_content['shared_question_id'] == '' ||
1306
            !is_numeric($form_content['shared_question_id'])
1307
        ) {
1308
            // Finding the max sort order of the questions in the given survey
1309
            $sql = "SELECT max(sort) AS max_sort FROM $tbl_survey_question
1310
                    WHERE survey_id='".intval($survey_data['survey_share'])."'
1311
                    AND code='".Database::escape_string($_course['id'])."'";
1312
            $result = Database::query($sql);
1313
            $row = Database::fetch_array($result, 'ASSOC');
1314
            $max_sort = $row['max_sort'];
1315
1316
            // Adding the question to the survey_question table
1317
            $sql = "INSERT INTO $tbl_survey_question (survey_id, survey_question, survey_question_comment, type, display, sort, code) VALUES (
1318
                    '".Database::escape_string($survey_data['survey_share'])."',
1319
                    '".Database::escape_string($form_content['question'])."',
1320
                    '".Database::escape_string($form_content['question_comment'])."',
1321
                    '".Database::escape_string($form_content['type'])."',
1322
                    '".Database::escape_string($form_content['horizontalvertical'])."',
1323
                    '".Database::escape_string($max_sort + 1)."',
1324
                    '".Database::escape_string($_course['id'])."')";
1325
            Database::query($sql);
1326
            $shared_question_id = Database::insert_id();
1327
        } else {
1328
            // Updating an existing question
1329
            // adding the question to the survey_question table
1330
            $sql = "UPDATE $tbl_survey_question SET
1331
                        survey_question = '".Database::escape_string($form_content['question'])."',
1332
                        survey_question_comment = '".Database::escape_string($form_content['question_comment'])."',
1333
                        display = '".Database::escape_string($form_content['horizontalvertical'])."'
1334
                    WHERE
1335
                        question_id = '".intval($form_content['shared_question_id'])."' AND
1336
                        code = '".Database::escape_string($_course['id'])."'";
1337
            Database::query($sql);
1338
            $shared_question_id = $form_content['shared_question_id'];
1339
        }
1340
1341
        return $shared_question_id;
1342
    }
1343
1344
    /**
1345
     * This functions moves a question of a survey up or down.
1346
     *
1347
     * @param string $direction
1348
     * @param int    $survey_question_id
1349
     * @param int    $survey_id
1350
     *
1351
     * @author Patrick Cool <[email protected]>, Ghent University
1352
     *
1353
     * @version January 2007
1354
     */
1355
    public static function move_survey_question(
1356
        $direction,
1357
        $survey_question_id,
1358
        $survey_id
1359
    ) {
1360
        // Table definition
1361
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1362
        $course_id = api_get_course_int_id();
1363
1364
        if ($direction == 'moveup') {
1365
            $sort = 'DESC';
1366
        }
1367
        if ($direction == 'movedown') {
1368
            $sort = 'ASC';
1369
        }
1370
1371
        $survey_id = (int) $survey_id;
1372
1373
        // Finding the two questions that needs to be swapped
1374
        $sql = "SELECT * FROM $table_survey_question
1375
		        WHERE c_id = $course_id AND survey_id='".$survey_id."'
1376
		        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...
1377
        $result = Database::query($sql);
1378
        $found = false;
1379
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1380
            if ($found) {
1381
                $question_id_two = $row['question_id'];
1382
                $question_sort_two = $row['sort'];
1383
                $found = false;
1384
            }
1385
            if ($row['question_id'] == $survey_question_id) {
1386
                $found = true;
1387
                $question_id_one = $row['question_id'];
1388
                $question_sort_one = $row['sort'];
1389
            }
1390
        }
1391
1392
        $sql = "UPDATE $table_survey_question 
1393
                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...
1394
		        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...
1395
        Database::query($sql);
1396
1397
        $sql = "UPDATE $table_survey_question 
1398
                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...
1399
		        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...
1400
        Database::query($sql);
1401
    }
1402
1403
    /**
1404
     * This function deletes all the questions of a given survey
1405
     * This function is normally only called when a survey is deleted.
1406
     *
1407
     * @param int $survey_id the id of the survey that has to be deleted
1408
     *
1409
     * @return bool
1410
     *
1411
     * @author Patrick Cool <[email protected]>, Ghent University
1412
     *
1413
     * @version January 2007
1414
     */
1415
    public static function delete_all_survey_questions($survey_id, $shared = false)
1416
    {
1417
        $course_id = api_get_course_int_id();
1418
        $survey_id = (int) $survey_id;
1419
1420
        // Table definitions
1421
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1422
        $course_condition = " c_id = $course_id AND ";
1423
        if ($shared) {
1424
            $course_condition = '';
1425
            $table_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1426
        }
1427
1428
        $sql = "DELETE FROM $table_survey_question
1429
		        WHERE $course_condition survey_id = '".$survey_id."'";
1430
1431
        // Deleting the survey questions
1432
        Database::query($sql);
1433
1434
        // Deleting all the options of the questions of the survey
1435
        self::delete_all_survey_questions_options($survey_id, $shared);
1436
1437
        // Deleting all the answers on this survey
1438
        self::delete_all_survey_answers($survey_id);
1439
1440
        return true;
1441
    }
1442
1443
    /**
1444
     * This function deletes a survey question and all its options.
1445
     *
1446
     * @param int  $survey_id   the id of the survey
1447
     * @param int  $question_id the id of the question
1448
     * @param bool $shared
1449
     *
1450
     * @todo also delete the answers to this question
1451
     *
1452
     * @author Patrick Cool <[email protected]>, Ghent University
1453
     *
1454
     * @version March 2007
1455
     */
1456
    public static function delete_survey_question($survey_id, $question_id, $shared = false)
1457
    {
1458
        $course_id = api_get_course_int_id();
1459
        if ($shared) {
1460
            self::delete_shared_survey_question($survey_id, $question_id);
1461
        }
1462
1463
        // Table definitions
1464
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1465
        // Deleting the survey questions
1466
        $sql = "DELETE FROM $table
1467
		        WHERE
1468
		            c_id = $course_id AND
1469
		            survey_id='".intval($survey_id)."' AND
1470
		            question_id='".intval($question_id)."'";
1471
        Database::query($sql);
1472
1473
        // Deleting the options of the question of the survey
1474
        self::delete_survey_question_option($survey_id, $question_id, $shared);
1475
    }
1476
1477
    /**
1478
     * This function deletes a shared survey question from the main database and all its options.
1479
     *
1480
     * @param int $question_id the id of the question
1481
     *
1482
     * @todo delete all the options of this question
1483
     *
1484
     * @author Patrick Cool <[email protected]>, Ghent University
1485
     *
1486
     * @version March 2007
1487
     */
1488
    public static function delete_shared_survey_question($survey_id, $question_id)
1489
    {
1490
        // Table definitions
1491
        $table_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1492
        $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1493
1494
        // First we have to get the shared_question_id
1495
        $question_data = self::get_question($question_id);
1496
1497
        // Deleting the survey questions
1498
        $sql = "DELETE FROM $table_survey_question
1499
		        WHERE question_id='".intval($question_data['shared_question_id'])."'";
1500
        Database::query($sql);
1501
1502
        // Deleting the options of the question of the survey question
1503
        $sql = "DELETE FROM $table_survey_question_option
1504
		        WHERE question_id='".intval($question_data['shared_question_id'])."'";
1505
        Database::query($sql);
1506
    }
1507
1508
    /**
1509
     * This function stores the options of the questions in the table.
1510
     *
1511
     * @param array $form_content
1512
     *
1513
     * @author Patrick Cool <[email protected]>, Ghent University
1514
     *
1515
     * @version January 2007
1516
     *
1517
     * @todo writing the update statement when editing a question
1518
     */
1519
    public static function save_question_options($form_content, $survey_data)
1520
    {
1521
        $course_id = api_get_course_int_id();
1522
        // A percentage question type has options 1 -> 100
1523
        if ($form_content['type'] === 'percentage') {
1524
            for ($i = 1; $i < 101; $i++) {
1525
                $form_content['answers'][] = $i;
1526
            }
1527
        }
1528
1529
        if (is_numeric($survey_data['survey_share']) && $survey_data['survey_share'] != 0) {
1530
            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

1530
            self::/** @scrutinizer ignore-call */ 
1531
                  save_shared_question_options($form_content, $survey_data);
Loading history...
1531
        }
1532
1533
        // Table definition
1534
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1535
1536
        // We are editing a question so we first have to remove all the existing options from the database
1537
        if (is_numeric($form_content['question_id'])) {
1538
            $sql = "DELETE FROM $table_survey_question_option
1539
			        WHERE c_id = $course_id AND question_id = '".intval($form_content['question_id'])."'";
1540
            Database::query($sql);
1541
        }
1542
1543
        $counter = 1;
1544
        $em = Database::getManager();
1545
        if (isset($form_content['answers']) && is_array($form_content['answers'])) {
1546
            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...
1547
                $values = isset($form_content['values']) ? $form_content['values'][$i] : 0;
1548
                $option = new CSurveyQuestionOption();
1549
                $option
1550
                    ->setCId($course_id)
1551
                    ->setQuestionId($form_content['question_id'])
1552
                    ->setSurveyId($form_content['survey_id'])
1553
                    ->setOptionText($form_content['answers'][$i])
1554
                    ->setValue($values)
1555
                    ->setSort($counter)
1556
                ;
1557
1558
                $em->persist($option);
1559
                $em->flush();
1560
1561
                $insertId = $option->getIid();
1562
                if ($insertId) {
1563
                    $sql = "UPDATE $table_survey_question_option
1564
                            SET question_option_id = $insertId
1565
                            WHERE iid = $insertId";
1566
                    Database::query($sql);
1567
1568
                    $counter++;
1569
                }
1570
            }
1571
        }
1572
    }
1573
1574
    /**
1575
     * This function stores the options of the questions in the shared table.
1576
     *
1577
     * @param array $form_content
1578
     *
1579
     * @author Patrick Cool <[email protected]>, Ghent University
1580
     *
1581
     * @version February 2007
1582
     *
1583
     * @todo writing the update statement when editing a question
1584
     */
1585
    public function save_shared_question_options($form_content, $survey_data)
1586
    {
1587
        if (is_array($form_content) && is_array($form_content['answers'])) {
1588
            // Table definition
1589
            $table = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1590
1591
            // We are editing a question so we first have to remove all the existing options from the database
1592
            $sql = "DELETE FROM $table
1593
                    WHERE question_id = '".Database::escape_string($form_content['shared_question_id'])."'";
1594
            Database::query($sql);
1595
1596
            $counter = 1;
1597
            foreach ($form_content['answers'] as &$answer) {
1598
                $params = [
1599
                    'question_id' => $form_content['shared_question_id'],
1600
                    'survey_id' => $survey_data['is_shared'],
1601
                    'option_text' => $answer,
1602
                    'sort' => $counter,
1603
                ];
1604
                Database::insert($table, $params);
1605
1606
                $counter++;
1607
            }
1608
        }
1609
    }
1610
1611
    /**
1612
     * This function deletes all the options of the questions of a given survey
1613
     * This function is normally only called when a survey is deleted.
1614
     *
1615
     * @param int $survey_id the id of the survey that has to be deleted
1616
     *
1617
     * @return true
1618
     *
1619
     * @author Patrick Cool <[email protected]>, Ghent University
1620
     *
1621
     * @version January 2007
1622
     */
1623
    public static function delete_all_survey_questions_options($survey_id, $shared = false)
1624
    {
1625
        // Table definitions
1626
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1627
        $course_id = api_get_course_int_id();
1628
        $course_condition = " c_id = $course_id AND ";
1629
        if ($shared) {
1630
            $course_condition = '';
1631
            $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1632
        }
1633
1634
        $sql = "DELETE FROM $table_survey_question_option
1635
                WHERE $course_condition survey_id='".intval($survey_id)."'";
1636
1637
        // Deleting the options of the survey questions
1638
        Database::query($sql);
1639
1640
        return true;
1641
    }
1642
1643
    /**
1644
     * This function deletes the options of a given question.
1645
     *
1646
     * @param int  $survey_id
1647
     * @param int  $question_id
1648
     * @param bool $shared
1649
     *
1650
     * @return bool
1651
     *
1652
     * @author Patrick Cool <[email protected]>, Ghent University
1653
     * @author Julio Montoya
1654
     *
1655
     * @version March 2007
1656
     */
1657
    public static function delete_survey_question_option(
1658
        $survey_id,
1659
        $question_id,
1660
        $shared = false
1661
    ) {
1662
        $course_id = api_get_course_int_id();
1663
        $course_condition = " c_id = $course_id AND ";
1664
1665
        // Table definitions
1666
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1667
        if ($shared) {
1668
            $course_condition = '';
1669
            $table = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1670
        }
1671
1672
        // Deleting the options of the survey questions
1673
        $sql = "DELETE FROM $table
1674
		        WHERE
1675
		            $course_condition survey_id='".intval($survey_id)."' AND
1676
		            question_id='".intval($question_id)."'";
1677
        Database::query($sql);
1678
1679
        return true;
1680
    }
1681
1682
    /**
1683
     * SURVEY ANSWERS FUNCTIONS.
1684
     */
1685
1686
    /**
1687
     * This function deletes all the answers anyone has given on this survey
1688
     * This function is normally only called when a survey is deleted.
1689
     *
1690
     * @param $survey_id the id of the survey that has to be deleted
1691
     *
1692
     * @return true
1693
     *
1694
     * @todo write the function
1695
     *
1696
     * @author Patrick Cool <[email protected]>, Ghent University
1697
     *
1698
     * @version January 2007,december 2008
1699
     */
1700
    public static function delete_all_survey_answers($survey_id)
1701
    {
1702
        $course_id = api_get_course_int_id();
1703
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1704
        $survey_id = (int) $survey_id;
1705
        $sql = "DELETE FROM $table 
1706
                WHERE c_id = $course_id AND survey_id=$survey_id";
1707
        Database::query($sql);
1708
1709
        return true;
1710
    }
1711
1712
    /**
1713
     * @param int $user_id
1714
     * @param int $survey_id
1715
     * @param int $course_id
1716
     *
1717
     * @return bool
1718
     */
1719
    public static function is_user_filled_survey($user_id, $survey_id, $course_id)
1720
    {
1721
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1722
        $user_id = (int) $user_id;
1723
        $course_id = (int) $course_id;
1724
        $survey_id = (int) $survey_id;
1725
1726
        $sql = "SELECT DISTINCT user 
1727
                FROM $table
1728
                WHERE
1729
                    c_id		= $course_id AND
1730
                    user		= $user_id AND
1731
                    survey_id	= $survey_id";
1732
        $result = Database::query($sql);
1733
        if (Database::num_rows($result)) {
1734
            return true;
1735
        }
1736
1737
        return false;
1738
    }
1739
1740
    /**
1741
     * This function gets all the persons who have filled the survey.
1742
     *
1743
     * @param int $survey_id
1744
     *
1745
     * @return array
1746
     *
1747
     * @author Patrick Cool <[email protected]>, Ghent University
1748
     *
1749
     * @version February 2007
1750
     */
1751
    public static function get_people_who_filled_survey(
1752
        $survey_id,
1753
        $all_user_info = false,
1754
        $course_id = null
1755
    ) {
1756
        // Database table definition
1757
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1758
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1759
1760
        // Variable initialisation
1761
        $return = [];
1762
1763
        if (empty($course_id)) {
1764
            $course_id = api_get_course_int_id();
1765
        } else {
1766
            $course_id = (int) $course_id;
1767
        }
1768
1769
        $survey_id = (int) $survey_id;
1770
1771
        if ($all_user_info) {
1772
            $order_clause = api_sort_by_first_name()
1773
                ? ' ORDER BY user.firstname, user.lastname'
1774
                : ' ORDER BY user.lastname, user.firstname';
1775
            $sql = "SELECT DISTINCT
1776
			            answered_user.user as invited_user, 
1777
			            user.firstname, 
1778
			            user.lastname, 
1779
			            user.user_id
1780
                    FROM $table_survey_answer answered_user
1781
                    LEFT JOIN $table_user as user ON answered_user.user = user.user_id
1782
                    WHERE
1783
                        answered_user.c_id = $course_id AND
1784
                        survey_id= '".$survey_id."' ".
1785
                $order_clause;
1786
        } else {
1787
            $sql = "SELECT DISTINCT user FROM $table_survey_answer
1788
			        WHERE c_id = $course_id AND survey_id= '".$survey_id."'  ";
1789
        }
1790
1791
        $res = Database::query($sql);
1792
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1793
            if ($all_user_info) {
1794
                $userInfo = api_get_user_info($row['user_id']);
1795
                $row['user_info'] = $userInfo;
1796
                $return[] = $row;
1797
            } else {
1798
                $return[] = $row['user'];
1799
            }
1800
        }
1801
1802
        return $return;
1803
    }
1804
1805
    /**
1806
     * @return bool
1807
     */
1808
    public static function survey_generation_hash_available()
1809
    {
1810
        if (extension_loaded('mcrypt')) {
1811
            return true;
1812
        }
1813
1814
        return false;
1815
    }
1816
1817
    /**
1818
     * @param int $survey_id
1819
     * @param int $course_id
1820
     * @param int $session_id
1821
     * @param int $group_id
1822
     *
1823
     * @return string
1824
     */
1825
    public static function generate_survey_hash($survey_id, $course_id, $session_id, $group_id)
1826
    {
1827
        $hash = hash('sha512', api_get_security_key().'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id);
1828
1829
        return $hash;
1830
    }
1831
1832
    /**
1833
     * @param int    $survey_id
1834
     * @param int    $course_id
1835
     * @param int    $session_id
1836
     * @param int    $group_id
1837
     * @param string $hash
1838
     *
1839
     * @return bool
1840
     */
1841
    public static function validate_survey_hash($survey_id, $course_id, $session_id, $group_id, $hash)
1842
    {
1843
        $generatedHash = self::generate_survey_hash($survey_id, $course_id, $session_id, $group_id);
1844
        if ($generatedHash == $hash) {
1845
            return true;
1846
        }
1847
1848
        return false;
1849
    }
1850
1851
    /**
1852
     * @param int $survey_id
1853
     * @param int $course_id
1854
     * @param int $session_id
1855
     * @param int $group_id
1856
     *
1857
     * @return string
1858
     */
1859
    public static function generate_survey_link(
1860
        $survey_id,
1861
        $course_id,
1862
        $session_id,
1863
        $group_id
1864
    ) {
1865
        $code = self::generate_survey_hash(
1866
            $survey_id,
1867
            $course_id,
1868
            $session_id,
1869
            $group_id
1870
        );
1871
1872
        return api_get_path(WEB_CODE_PATH).'survey/link.php?h='.$code.'&i='.$survey_id.'&c='.intval($course_id).'&s='
1873
            .intval($session_id).'&g='.$group_id;
1874
    }
1875
1876
    /**
1877
     * Check if the current user has mandatory surveys no-answered
1878
     * and redirect to fill the first found survey.
1879
     */
1880
    public static function protectByMandatory()
1881
    {
1882
        if (strpos($_SERVER['SCRIPT_NAME'], 'fillsurvey.php') !== false) {
1883
            return;
1884
        }
1885
1886
        $userId = api_get_user_id();
1887
        $courseId = api_get_course_int_id();
1888
        $sessionId = api_get_session_id();
1889
1890
        if (!$userId) {
1891
            return;
1892
        }
1893
1894
        if (!$courseId) {
1895
            return;
1896
        }
1897
1898
        try {
1899
            /** @var CSurveyInvitation $invitation */
1900
            $invitation = Database::getManager()
1901
                ->createQuery("
1902
                    SELECT i FROM ChamiloCourseBundle:CSurveyInvitation i
1903
                    INNER JOIN ChamiloCourseBundle:CSurvey s
1904
                        WITH (s.code = i.surveyCode AND s.cId = i.cId AND s.sessionId = i.sessionId)
1905
                    INNER JOIN ChamiloCoreBundle:ExtraFieldValues efv WITH efv.itemId = s.iid
1906
                    INNER JOIN ChamiloCoreBundle:ExtraField ef WITH efv.field = ef.id
1907
                    WHERE 
1908
                        i.answered = 0 AND 
1909
                        i.cId = :course AND 
1910
                        i.user = :user AND 
1911
                        i.sessionId = :session AND 
1912
                        :now BETWEEN s.availFrom AND s.availTill AND 
1913
                        ef.variable = :variable AND 
1914
                        efv.value = 1 AND 
1915
                        s.surveyType != 3
1916
                    ORDER BY s.availTill ASC
1917
                ")
1918
                ->setMaxResults(1)
1919
                ->setParameters([
1920
                    'course' => $courseId,
1921
                    'user' => $userId,
1922
                    'session' => $sessionId,
1923
                    'now' => new DateTime('UTC', new DateTimeZone('UTC')),
1924
                    'variable' => 'is_mandatory',
1925
                ])
1926
                ->getSingleResult();
1927
        } catch (Exception $e) {
1928
            $invitation = null;
1929
        }
1930
1931
        if (!$invitation) {
1932
            return;
1933
        }
1934
1935
        $urlParams = http_build_query([
1936
            'course' => api_get_course_id(),
1937
            'invitationcode' => $invitation->getInvitationCode(),
1938
        ]);
1939
1940
        Display::addFlash(
1941
            Display::return_message(get_lang('MandatorySurveyNoAnswered'), 'warning')
1942
        );
1943
1944
        header('Location: '.api_get_path(WEB_CODE_PATH).'survey/fillsurvey.php?'.$urlParams.'&'.api_get_cidreq());
1945
        exit;
1946
    }
1947
1948
    /**
1949
     * This function empty surveys (invitations and answers).
1950
     *
1951
     * @param int $surveyId id of the survey to empty
1952
     *
1953
     * @return bool
1954
     */
1955
    public static function emptySurveyFromId($surveyId)
1956
    {
1957
        // Database table definitions
1958
        $surveyInvitationTable = Database:: get_course_table(TABLE_SURVEY_INVITATION);
1959
        $surveyAnswerTable = Database:: get_course_table(TABLE_SURVEY_ANSWER);
1960
        $surveyTable = Database:: get_course_table(TABLE_SURVEY);
1961
        $surveyId = (int) $surveyId;
1962
        $surveyData = self::get_survey($surveyId);
1963
        if (empty($surveyData)) {
1964
            return false;
1965
        }
1966
1967
        $surveyCode = $surveyData['survey_code'];
1968
        $courseId = (int) $surveyData['c_id'];
1969
        $sessionId = (int) $surveyData['session_id'];
1970
1971
        $sql = "DELETE FROM $surveyInvitationTable 
1972
                WHERE session_id = $sessionId AND c_id = $courseId AND survey_code = '$surveyCode' ";
1973
        Database::query($sql);
1974
1975
        $sql = "DELETE FROM $surveyAnswerTable 
1976
               WHERE survey_id = $surveyId AND c_id = $courseId ";
1977
        Database::query($sql);
1978
1979
        $sql = "UPDATE $surveyTable 
1980
                SET invited = 0, answered = 0 
1981
                WHERE survey_id = $surveyId AND c_id = $courseId AND session_id = $sessionId ";
1982
        Database::query($sql);
1983
1984
        return true;
1985
    }
1986
1987
    /**
1988
     * This function copy survey specifying course id and session id where will be copied.
1989
     *
1990
     * @param int $surveyId
1991
     * @param int $targetCourseId  target course id
1992
     * @param int $targetSessionId target session id
1993
     *
1994
     * @return bool|int when fails or return the new survey id
1995
     */
1996
    public static function copySurveySession($surveyId, $targetCourseId, $targetSessionId)
1997
    {
1998
        // Database table definitions
1999
        $surveyTable = Database::get_course_table(TABLE_SURVEY);
2000
        $surveyQuestionGroupTable = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
2001
        $surveyQuestionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
2002
        $surveyOptionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2003
        $surveyId = (int) $surveyId;
2004
        $targetCourseId = (int) $targetCourseId;
2005
        $targetSessionId = (int) $targetSessionId;
2006
2007
        $surveyData = self::get_survey($surveyId, 0, '', true);
2008
        if (empty($surveyData) || empty($targetCourseId)) {
2009
            return false;
2010
        }
2011
2012
        $originalCourseId = $surveyData['c_id'];
2013
        $originalSessionId = $surveyData['session_id'];
2014
2015
        $surveyData['code'] = self::generate_unique_code($surveyData['code']);
2016
        $surveyData['c_id'] = $targetCourseId;
2017
        $surveyData['session_id'] = $targetSessionId;
2018
        // Add a "Copy" suffix if copied inside the same course
2019
        if ($targetCourseId == $originalCourseId) {
2020
            $surveyData['title'] = $surveyData['title'].' '.get_lang('Copy');
2021
        }
2022
        unset($surveyData['iid']);
2023
        unset($surveyData['id']);
2024
2025
        $newSurveyId = Database::insert($surveyTable, $surveyData);
2026
2027
        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...
2028
            $sql = "UPDATE $surveyTable SET survey_id = $newSurveyId 
2029
                    WHERE iid = $newSurveyId";
2030
            Database::query($sql);
2031
2032
            $sql = "SELECT * FROM $surveyQuestionGroupTable 
2033
                    WHERE survey_id = $surveyId AND c_id = $originalCourseId ";
2034
            $res = Database::query($sql);
2035
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2036
                $params = [
2037
                    'c_id' => $targetCourseId,
2038
                    'name' => $row['name'],
2039
                    'description' => $row['description'],
2040
                    'survey_id' => $newSurveyId,
2041
                ];
2042
                $insertId = Database::insert($surveyQuestionGroupTable, $params);
2043
                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...
2044
                    $sql = "UPDATE $surveyQuestionGroupTable SET id = iid WHERE iid = $insertId";
2045
                    Database::query($sql);
2046
                    $group_id[$row['id']] = $insertId;
2047
                }
2048
            }
2049
2050
            // Get questions
2051
            $sql = "SELECT * FROM $surveyQuestionTable 
2052
                    WHERE survey_id = $surveyId AND c_id = $originalCourseId";
2053
            $res = Database::query($sql);
2054
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2055
                $params = [
2056
                    'c_id' => $targetCourseId,
2057
                    'survey_id' => $newSurveyId,
2058
                    'survey_question' => $row['survey_question'],
2059
                    'survey_question_comment' => $row['survey_question_comment'],
2060
                    'type' => $row['type'],
2061
                    'display' => $row['display'],
2062
                    'sort' => $row['sort'],
2063
                    'shared_question_id' => $row['shared_question_id'],
2064
                    'max_value' => $row['max_value'],
2065
                    'survey_group_pri' => $row['survey_group_pri'],
2066
                    'survey_group_sec1' => $row['survey_group_sec1'],
2067
                    'survey_group_sec2' => $row['survey_group_sec2'],
2068
                ];
2069
                $insertId = Database::insert($surveyQuestionTable, $params);
2070
                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...
2071
                    $sql = "UPDATE $surveyQuestionTable 
2072
                            SET question_id = iid
2073
                            WHERE iid = $insertId";
2074
                    Database::query($sql);
2075
2076
                    $question_id[$row['question_id']] = $insertId;
2077
                }
2078
            }
2079
2080
            // Get questions options
2081
            $sql = "SELECT * FROM $surveyOptionsTable 
2082
                    WHERE survey_id = $surveyId AND c_id = $originalCourseId";
2083
2084
            $res = Database::query($sql);
2085
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2086
                $params = [
2087
                    'c_id' => $targetCourseId,
2088
                    '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...
2089
                    'survey_id' => $newSurveyId,
2090
                    'option_text' => $row['option_text'],
2091
                    'sort' => $row['sort'],
2092
                    'value' => $row['value'],
2093
                ];
2094
                $insertId = Database::insert($surveyOptionsTable, $params);
2095
                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...
2096
                    $sql = "UPDATE $surveyOptionsTable SET question_option_id = $insertId WHERE iid = $insertId";
2097
                    Database::query($sql);
2098
                }
2099
            }
2100
2101
            return $newSurveyId;
2102
        }
2103
2104
        return false;
2105
    }
2106
2107
    /**
2108
     * @param array $surveyData
2109
     *
2110
     * @return bool
2111
     */
2112
    public static function removeMultiplicateQuestions($surveyData)
2113
    {
2114
        if (empty($surveyData)) {
2115
            return false;
2116
        }
2117
        $surveyId = $surveyData['survey_id'];
2118
        $courseId = $surveyData['c_id'];
2119
2120
        if (empty($surveyId) || empty($courseId)) {
2121
            return false;
2122
        }
2123
2124
        $questions = self::get_questions($surveyId);
2125
        foreach ($questions as $question) {
2126
            // Questions marked with "geneated" were created using the "multiplicate" feature.
2127
            if ($question['survey_question_comment'] === 'generated') {
2128
                self::delete_survey_question($surveyId, $question['question_id']);
2129
            }
2130
        }
2131
    }
2132
2133
    /**
2134
     * @param array $surveyData
2135
     *
2136
     * @return bool
2137
     */
2138
    public static function multiplicateQuestions($surveyData)
2139
    {
2140
        if (empty($surveyData)) {
2141
            return false;
2142
        }
2143
        $surveyId = $surveyData['survey_id'];
2144
        $courseId = $surveyData['c_id'];
2145
2146
        if (empty($surveyId) || empty($courseId)) {
2147
            return false;
2148
        }
2149
2150
        $questions = self::get_questions($surveyId);
2151
2152
        $obj = new UserGroup();
2153
2154
        $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...
2155
        $classList = $obj->getUserGroupInCourse($options);
2156
2157
        $classTag = '{{class_name}}';
2158
        $studentTag = '{{student_full_name}}';
2159
        $classCounter = 0;
2160
        foreach ($classList as $class) {
2161
            $className = $class['name'];
2162
            foreach ($questions as $question) {
2163
                $users = $obj->get_users_by_usergroup($class['id']);
2164
                if (empty($users)) {
2165
                    continue;
2166
                }
2167
2168
                $text = $question['question'];
2169
                if (strpos($text, $classTag) !== false) {
2170
                    $replacedText = str_replace($classTag, $className, $text);
2171
                    $values = [
2172
                        'c_id' => $courseId,
2173
                        'question_comment' => 'generated',
2174
                        'type' => $question['type'],
2175
                        'display' => $question['horizontalvertical'],
2176
                        'question' => $replacedText,
2177
                        'survey_id' => $surveyId,
2178
                        'question_id' => 0,
2179
                        'shared_question_id' => 0,
2180
                    ];
2181
                    self::save_question($surveyData, $values);
2182
                    $classCounter++;
2183
                    continue;
2184
                }
2185
2186
                foreach ($users as $userId) {
2187
                    $userInfo = api_get_user_info($userId);
2188
2189
                    if (strpos($text, $studentTag) !== false) {
2190
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
2191
                        $values = [
2192
                            'c_id' => $courseId,
2193
                            'question_comment' => 'generated',
2194
                            'type' => $question['type'],
2195
                            'display' => $question['horizontalvertical'],
2196
                            'maximum_score' => $question['maximum_score'],
2197
                            'question' => $replacedText,
2198
                            'survey_id' => $surveyId,
2199
                            'question_id' => 0,
2200
                            'shared_question_id' => 0,
2201
                        ];
2202
2203
                        $answers = [];
2204
                        if (!empty($question['answers'])) {
2205
                            foreach ($question['answers'] as $answer) {
2206
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
2207
                                $answers[] = $replacedText;
2208
                            }
2209
                        }
2210
                        $values['answers'] = $answers;
2211
                        self::save_question($surveyData, $values);
2212
                    }
2213
                }
2214
2215
                if ($classCounter < count($classList)) {
2216
                    // Add end page
2217
                    $values = [
2218
                        'c_id' => $courseId,
2219
                        'question_comment' => 'generated',
2220
                        'type' => 'pagebreak',
2221
                        'display' => 'horizontal',
2222
                        'question' => get_lang('QuestionForNextClass'),
2223
                        'survey_id' => $surveyId,
2224
                        'question_id' => 0,
2225
                        'shared_question_id' => 0,
2226
                    ];
2227
                    self::save_question($surveyData, $values);
2228
                }
2229
            }
2230
        }
2231
    }
2232
2233
    /**
2234
     * @param array $survey
2235
     *
2236
     * @return int
2237
     */
2238
    public static function getCountPages($survey)
2239
    {
2240
        if (empty($survey) || !isset($survey['iid'])) {
2241
            return 0;
2242
        }
2243
2244
        $courseId = $survey['c_id'];
2245
        $surveyId = $survey['survey_id'];
2246
2247
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
2248
2249
        // One question per page
2250
        $sql = "SELECT * FROM $table
2251
                WHERE
2252
                    survey_question NOT LIKE '%{{%' AND
2253
                    type = 'pagebreak' AND
2254
                    c_id = $courseId AND
2255
                    survey_id = $surveyId";
2256
        $result = Database::query($sql);
2257
        $numberPageBreaks = Database::num_rows($result);
2258
2259
        // One question per page
2260
        $sql = "SELECT * FROM $table
2261
                    WHERE
2262
                        survey_question NOT LIKE '%{{%' AND
2263
                        type != 'pagebreak' AND
2264
                        c_id = $courseId AND
2265
                    survey_id = $surveyId";
2266
        $result = Database::query($sql);
2267
        $countOfQuestions = Database::num_rows($result);
2268
        $count = 1;
2269
        if (!empty($numberPageBreaks) && !empty($countOfQuestions)) {
2270
            $count = $countOfQuestions;
2271
        }
2272
2273
        if ($survey['one_question_per_page'] == 1) {
2274
            $count = 1;
2275
            if (!empty($countOfQuestions)) {
2276
                $count = $countOfQuestions;
2277
            }
2278
        } else {
2279
            $count = $numberPageBreaks * 2;
2280
            if (empty($numberPageBreaks)) {
2281
                $count = 1;
2282
            }
2283
        }
2284
2285
        return $count;
2286
    }
2287
2288
    /**
2289
     * Check whether this survey has ended. If so, display message and exit rhis script.
2290
     *
2291
     * @param array $surveyData Survey data
2292
     */
2293
    public static function checkTimeAvailability($surveyData)
2294
    {
2295
        if (empty($surveyData)) {
2296
            api_not_allowed(true);
2297
        }
2298
2299
        $allowSurveyAvailabilityDatetime = api_get_configuration_value('allow_survey_availability_datetime');
2300
        $utcZone = new DateTimeZone('UTC');
2301
        $startDate = new DateTime($surveyData['start_date'], $utcZone);
2302
        $endDate = new DateTime($surveyData['end_date'], $utcZone);
2303
        $currentDate = new DateTime('now', $utcZone);
2304
        if (!$allowSurveyAvailabilityDatetime) {
2305
            $currentDate->modify('today');
2306
        }
2307
        if ($currentDate < $startDate) {
2308
            api_not_allowed(
2309
                true,
2310
                Display:: return_message(
2311
                    get_lang('SurveyNotAvailableYet'),
2312
                    'warning',
2313
                    false
2314
                )
2315
            );
2316
        }
2317
2318
        if ($currentDate > $endDate) {
2319
            api_not_allowed(
2320
                true,
2321
                Display:: return_message(
2322
                    get_lang('SurveyNotAvailableAnymore'),
2323
                    'warning',
2324
                    false
2325
                )
2326
            );
2327
        }
2328
    }
2329
}
2330