Passed
Push — master ( afb2ec...e80e7a )
by Julito
09:13
created

SurveyManager::store_shared_survey()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 44
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

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

323
                        $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...
324
                        if (false === $pos) {
325
                            $row['survey_version'] = $row['survey_version'] + 1;
326
                            $versionValue = $row['survey_version'];
327
                        } else {
328
                            $getlast = explode('\.', $row['survey_version']);
329
                            $lastversion = array_pop($getlast);
330
                            $lastversion = $lastversion + 1;
331
                            $add = implode('.', $getlast);
332
                            if ('' != $add) {
333
                                $insertnewversion = $add.'.'.$lastversion;
334
                            } else {
335
                                $insertnewversion = $lastversion;
336
                            }
337
                            $versionValue = $insertnewversion;
338
                        }
339
                    }
340
                    $survey->setSurveyVersion($versionValue);
341
                }
342
            }
343
344
            $from = api_get_utc_datetime($values['start_date'].'00:00:00', true, true);
345
            $until = api_get_utc_datetime($values['end_date'].'23:59:59', true, true);
346
            if ($allowSurveyAvailabilityDatetime) {
347
                $from = api_get_utc_datetime($values['start_date'].':00', true, true);
348
                $until = api_get_utc_datetime($values['end_date'].':59', true, true);
349
            }
350
351
            $survey
352
                ->setCId($course_id)
353
                ->setCode(self::generateSurveyCode($values['survey_code']))
354
                ->setTitle($values['survey_title'])
355
                ->setSubtitle($values['survey_title'])
356
                ->setAuthor($_user['user_id'])
357
                ->setLang($values['survey_language'])
358
                ->setAvailFrom($from)
359
                ->setAvailTill($until)
360
                ->setIsShared($shared_survey_id)
361
                ->setTemplate('template')
362
                ->setIntro($values['survey_introduction'])
363
                ->setSurveyThanks($values['survey_thanks'])
364
                ->setAnonymous($values['anonymous'])
365
                ->setSessionId(api_get_session_id())
366
                ->setVisibleResults($values['visible_results'])
367
            ;
368
369
            $em = Database::getManager();
370
            $em->persist($survey);
371
            $em->flush();
372
373
            $survey_id = $survey->getIid();
374
            if ($survey_id > 0) {
375
                Event::addEvent(
0 ignored issues
show
Bug introduced by
The method addEvent() does not exist on Event. ( Ignorable by Annotation )

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

375
                Event::/** @scrutinizer ignore-call */ 
376
                       addEvent(

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

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

Loading history...
376
                    LOG_SURVEY_CREATED,
377
                    LOG_SURVEY_ID,
378
                    $survey_id,
379
                    null,
380
                    api_get_user_id(),
381
                    api_get_course_int_id(),
382
                    api_get_session_id()
383
                );
384
385
                // Insert into item_property
386
                api_item_property_update(
0 ignored issues
show
Bug introduced by
The function api_item_property_update was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

386
                /** @scrutinizer ignore-call */ 
387
                api_item_property_update(
Loading history...
387
                    api_get_course_info(),
388
                    TOOL_SURVEY,
389
                    $survey_id,
390
                    'SurveyAdded',
391
                    api_get_user_id()
392
                );
393
            }
394
395
            if (1 == $values['survey_type'] && !empty($values['parent_id'])) {
396
                self::copy_survey($values['parent_id'], $survey_id);
397
            }
398
399
            Display::addFlash(
400
                Display::return_message(
401
                    get_lang('The survey has been created succesfully'),
402
                    'success'
403
                )
404
            );
405
            $return['id'] = $survey_id;
406
        } else {
407
            // Check whether the code doesn't soon exists in this language
408
            $sql = 'SELECT 1 FROM '.$table_survey.'
409
			        WHERE
410
			            c_id = '.$course_id.' AND
411
			            code = "'.Database::escape_string($values['survey_code']).'" AND
412
			            lang = "'.Database::escape_string($values['survey_language']).'" AND
413
			            survey_id !='.intval($values['survey_id']);
414
            $rs = Database::query($sql);
415
            if (Database::num_rows($rs) > 0) {
416
                Display::addFlash(
417
                    Display::return_message(
418
                        get_lang('This survey code soon exists in this language'),
419
                        'error'
420
                    )
421
                );
422
                $return['type'] = 'error';
423
                $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0;
424
425
                return $return;
426
            }
427
428
            if (!isset($values['anonymous'])
429
                || (isset($values['anonymous']) && '' == $values['anonymous'])
430
            ) {
431
                $values['anonymous'] = 0;
432
            }
433
434
            $extraParams = [];
435
            $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0;
436
            $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : 0;
437
438
            if (0 == $values['anonymous']) {
439
                $extraParams['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0;
440
                if (1 == $extraParams['show_form_profile']) {
441
                    $fields = explode(',', $values['input_name_list']);
442
                    $field_values = '';
443
                    foreach ($fields as &$field) {
444
                        if ('' != $field) {
445
                            if (!isset($values[$field]) ||
446
                                (isset($values[$field]) && '' == $values[$field])
447
                            ) {
448
                                $values[$field] = 0;
449
                            }
450
                            $field_values .= $field.':'.$values[$field].'@';
451
                        }
452
                    }
453
                    $extraParams['form_fields'] = $field_values;
454
                } else {
455
                    $extraParams['form_fields'] = '';
456
                }
457
            } else {
458
                $extraParams['show_form_profile'] = 0;
459
                $extraParams['form_fields'] = '';
460
            }
461
462
            $params = [
463
                'title' => $values['survey_title'],
464
                'subtitle' => $values['survey_subtitle'],
465
                'author' => $_user['user_id'],
466
                'lang' => $values['survey_language'],
467
                'avail_from' => $allowSurveyAvailabilityDatetime
468
                    ? api_get_utc_datetime($values['start_date'].':00')
469
                    : $values['start_date'],
470
                'avail_till' => $allowSurveyAvailabilityDatetime
471
                    ? api_get_utc_datetime($values['end_date'].':59')
472
                    : $values['end_date'],
473
                'is_shared' => $shared_survey_id,
474
                'template' => 'template',
475
                'intro' => $values['survey_introduction'],
476
                'surveythanks' => $values['survey_thanks'],
477
                'anonymous' => $values['anonymous'],
478
                'session_id' => api_get_session_id(),
479
                'visible_results' => $values['visible_results'],
480
            ];
481
482
            $params = array_merge($params, $extraParams);
483
            Database::update(
484
                $table_survey,
485
                $params,
486
                [
487
                    'c_id = ? AND survey_id = ?' => [
488
                        $course_id,
489
                        $values['survey_id'],
490
                    ],
491
                ]
492
            );
493
494
            // Update into item_property (update)
495
            api_item_property_update(
496
                api_get_course_info(),
497
                TOOL_SURVEY,
498
                $values['survey_id'],
499
                'SurveyUpdated',
500
                api_get_user_id()
501
            );
502
503
            Display::addFlash(
504
                Display::return_message(
505
                    get_lang('The survey has been updated succesfully'),
506
                    'confirmation'
507
                )
508
            );
509
510
            $return['id'] = $values['survey_id'];
511
        }
512
513
        $survey_id = (int) $return['id'];
514
515
        // Gradebook
516
        $gradebook_option = false;
517
        if (isset($values['survey_qualify_gradebook'])) {
518
            $gradebook_option = $values['survey_qualify_gradebook'] > 0;
519
        }
520
521
        $gradebook_link_type = 8;
522
        $link_info = GradebookUtils::isResourceInCourseGradebook(
523
            $courseCode,
524
            $gradebook_link_type,
525
            $survey_id,
526
            $session_id
527
        );
528
529
        $gradebook_link_id = isset($link_info['id']) ? $link_info['id'] : false;
530
531
        if ($gradebook_option) {
532
            if ($survey_id > 0) {
533
                $title_gradebook = ''; // Not needed here.
534
                $description_gradebook = ''; // Not needed here.
535
                $survey_weight = floatval($_POST['survey_weight']);
536
                $max_score = 1;
537
538
                if (!$gradebook_link_id) {
539
                    GradebookUtils::add_resource_to_course_gradebook(
540
                        $values['category_id'],
541
                        $courseCode,
542
                        $gradebook_link_type,
543
                        $survey_id,
544
                        $title_gradebook,
545
                        $survey_weight,
546
                        $max_score,
547
                        $description_gradebook,
548
                        1,
549
                        $session_id
550
                    );
551
                } else {
552
                    GradebookUtils::updateResourceFromCourseGradebook(
553
                        $gradebook_link_id,
554
                        $courseCode,
555
                        $survey_weight
556
                    );
557
                }
558
            }
559
        } else {
560
            // Delete everything of the gradebook for this $linkId
561
            GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id);
562
        }
563
564
        return $return;
565
    }
566
567
    /**
568
     * This function stores a shared survey in the central database.
569
     *
570
     * @param array $values
571
     *
572
     * @return array $return the type of return message that has to be displayed and the message in it
573
     *
574
     * @author Patrick Cool <[email protected]>, Ghent University
575
     *
576
     * @version February 2007
577
     */
578
    public function store_shared_survey($values)
579
    {
580
        $_user = api_get_user_info();
581
        $_course = api_get_course_info();
582
583
        // Table definitions
584
        $table_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
585
586
        if (!$values['survey_id'] ||
587
            !is_numeric($values['survey_id']) ||
588
            'true' == $values['survey_share']['survey_share']
589
        ) {
590
            $sql = "INSERT INTO $table_survey (code, title, subtitle, author, lang, template, intro, surveythanks, creation_date, course_code) VALUES (
591
                    '".Database::escape_string($values['survey_code'])."',
592
                    '".Database::escape_string($values['survey_title'])."',
593
                    '".Database::escape_string($values['survey_subtitle'])."',
594
                    '".intval($_user['user_id'])."',
595
                    '".Database::escape_string($values['survey_language'])."',
596
                    '".Database::escape_string('template')."',
597
                    '".Database::escape_string($values['survey_introduction'])."',
598
                    '".Database::escape_string($values['survey_thanks'])."',
599
                    '".api_get_utc_datetime()."',
600
                    '".$_course['id']."')";
601
            Database::query($sql);
602
            $return = Database::insert_id();
603
604
            $sql = "UPDATE $table_survey SET survey_id = $return WHERE iid = $return";
605
            Database::query($sql);
606
        } else {
607
            $sql = "UPDATE $table_survey SET
608
                        code 			= '".Database::escape_string($values['survey_code'])."',
609
                        title 			= '".Database::escape_string($values['survey_title'])."',
610
                        subtitle 		= '".Database::escape_string($values['survey_subtitle'])."',
611
                        author 			= '".intval($_user['user_id'])."',
612
                        lang 			= '".Database::escape_string($values['survey_language'])."',
613
                        template 		= '".Database::escape_string('template')."',
614
                        intro			= '".Database::escape_string($values['survey_introduction'])."',
615
                        surveythanks	= '".Database::escape_string($values['survey_thanks'])."'
616
					WHERE survey_id = '".Database::escape_string($values['survey_share']['survey_share'])."'";
617
            Database::query($sql);
618
            $return = $values['survey_share']['survey_share'];
619
        }
620
621
        return $return;
622
    }
623
624
    /**
625
     * This function deletes a survey (and also all the question in that survey.
626
     *
627
     * @param int  $survey_id id of the survey that has to be deleted
628
     * @param bool $shared
629
     * @param int  $course_id
630
     *
631
     * @return true
632
     *
633
     * @author Patrick Cool <[email protected]>, Ghent University
634
     *
635
     * @version January 2007
636
     */
637
    public static function delete_survey($survey_id, $shared = false, $course_id = 0)
638
    {
639
        // Database table definitions
640
        if (empty($course_id)) {
641
            $course_id = api_get_course_int_id();
642
        }
643
644
        $survey_id = (int) $survey_id;
645
646
        if (empty($survey_id)) {
647
            return false;
648
        }
649
650
        $course_info = api_get_course_info_by_id($course_id);
651
        $course_id = $course_info['real_id'];
652
653
        $table_survey = Database::get_course_table(TABLE_SURVEY);
654
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
655
656
        if ($shared) {
657
            $table_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
658
            // Deleting the survey
659
            $sql = "DELETE FROM $table_survey
660
                    WHERE survey_id='".$survey_id."'";
661
            Database::query($sql);
662
        } else {
663
            $sql = "DELETE FROM $table_survey
664
                    WHERE c_id = $course_id AND survey_id='".$survey_id."'";
665
            Database::query($sql);
666
        }
667
668
        Event::addEvent(
669
            LOG_SURVEY_DELETED,
670
            LOG_SURVEY_ID,
671
            $survey_id,
672
            null,
673
            api_get_user_id(),
674
            api_get_course_int_id(),
675
            api_get_session_id()
676
        );
677
        // Deleting groups of this survey
678
        $sql = "DELETE FROM $table_survey_question_group
679
                WHERE c_id = $course_id AND survey_id='".$survey_id."'";
680
        Database::query($sql);
681
682
        // Deleting the questions of the survey
683
        self::delete_all_survey_questions($survey_id, $shared);
684
685
        // Update into item_property (delete)
686
        api_item_property_update(
0 ignored issues
show
Bug introduced by
The function api_item_property_update was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

686
        /** @scrutinizer ignore-call */ 
687
        api_item_property_update(
Loading history...
687
            $course_info,
688
            TOOL_SURVEY,
689
            $survey_id,
690
            'SurveyDeleted',
691
            api_get_user_id()
692
        );
693
694
        Skill::deleteSkillsFromItem($survey_id, ITEM_TYPE_SURVEY);
695
696
        return true;
697
    }
698
699
    /**
700
     * Copy given survey to a new (optional) given survey ID.
701
     *
702
     * @param int $survey_id
703
     * @param int $new_survey_id
704
     * @param int $targetCourseId
705
     *
706
     * @return bool
707
     */
708
    public static function copy_survey(
709
        $survey_id,
710
        $new_survey_id = null,
711
        $targetCourseId = null
712
    ) {
713
        $course_id = api_get_course_int_id();
714
        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...
715
            $targetCourseId = $course_id;
716
        }
717
718
        // Database table definitions
719
        $table_survey = Database::get_course_table(TABLE_SURVEY);
720
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
721
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
722
        $table_survey_options = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
723
        $survey_id = (int) $survey_id;
724
725
        // Get groups
726
        $survey_data = self::get_survey($survey_id, 0, null, true);
727
        if (empty($survey_data)) {
728
            return true;
729
        }
730
731
        if (empty($new_survey_id)) {
732
            $params = $survey_data;
733
            $params['code'] = self::generate_unique_code($params['code']);
734
            $params['c_id'] = $targetCourseId;
735
            unset($params['survey_id']);
736
            $params['session_id'] = api_get_session_id();
737
            $params['title'] = $params['title'].' '.get_lang('Copy');
738
            unset($params['iid']);
739
            $params['invited'] = 0;
740
            $params['answered'] = 0;
741
            $new_survey_id = Database::insert($table_survey, $params);
742
743
            if ($new_survey_id) {
744
                $sql = "UPDATE $table_survey SET survey_id = $new_survey_id
745
                        WHERE iid = $new_survey_id";
746
                Database::query($sql);
747
748
                // Insert into item_property
749
                api_item_property_update(
0 ignored issues
show
Bug introduced by
The function api_item_property_update was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

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

1201
                    /** @scrutinizer ignore-call */ 
1202
                    $shared_question_id = self::save_shared_question($form_content, $survey_data);
Loading history...
1202
                    $form_content['shared_question_id'] = $shared_question_id;
1203
                }
1204
1205
                // Storing a new question
1206
                if ('' == $form_content['question_id'] || !is_numeric($form_content['question_id'])) {
1207
                    // Finding the max sort order of the questions in the given survey
1208
                    $sql = "SELECT max(sort) AS max_sort
1209
					        FROM $tbl_survey_question
1210
                            WHERE c_id = $course_id AND survey_id = $surveyId ";
1211
                    $result = Database::query($sql);
1212
                    $row = Database::fetch_array($result, 'ASSOC');
1213
                    $max_sort = $row['max_sort'];
1214
1215
                    $question = new CSurveyQuestion();
1216
1217
                    // Some variables defined for survey-test type
1218
                    $extraParams = [];
1219
                    if (isset($_POST['choose'])) {
1220
                        if (1 == $_POST['choose']) {
1221
                            $question->setSurveyGroupPri($_POST['assigned']);
1222
                        } elseif (2 == $_POST['choose']) {
1223
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1224
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1225
                        }
1226
                    }
1227
1228
                    $question
1229
                        ->setSurveyQuestionComment($form_content['question_comment'] ?? '')
1230
                        ->setMaxValue($form_content['maximum_score'] ?? 0)
1231
                        ->setDisplay($form_content['horizontalvertical'] ?? '')
1232
                        ->setCId($course_id)
1233
                        ->setSurveyId($form_content['survey_id'])
1234
                        ->setSurveyQuestion($form_content['question'])
1235
                        ->setType($form_content['type'])
1236
                        ->setSort($max_sort + 1)
1237
                        ->setSharedQuestionId($form_content['shared_question_id'])
1238
                    ;
1239
1240
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1241
                        $question->setIsMandatory(isset($form_content['is_required']));
1242
                    }
1243
1244
                    if (api_get_configuration_value('survey_question_dependency')) {
1245
                        $params['parent_id'] = 0;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
1246
                        $params['parent_option_id'] = 0;
1247
                        if (isset($form_content['parent_id']) &&
1248
                            isset($form_content['parent_option_id']) &&
1249
                            !empty($form_content['parent_id']) &&
1250
                            !empty($form_content['parent_option_id'])
1251
                        ) {
1252
                            $params['parent_id'] = $form_content['parent_id'];
1253
                            $params['parent_option_id'] = $form_content['parent_option_id'];
1254
                        }
1255
                    }
1256
1257
                    $em = Database::getManager();
1258
                    $em->persist($question);
1259
                    $em->flush();
1260
1261
                    $question_id = $question->getIid();
1262
                    if ($question_id) {
1263
                        $sql = "UPDATE $tbl_survey_question SET question_id = $question_id
1264
                                WHERE iid = $question_id";
1265
                        Database::query($sql);
1266
1267
                        $form_content['question_id'] = $question_id;
1268
                        $return_message = 'QuestionAdded';
1269
                    }
1270
                } else {
1271
                    // Updating an existing question
1272
                    $extraParams = [];
1273
                    if (isset($_POST['choose'])) {
1274
                        if (1 == $_POST['choose']) {
1275
                            $extraParams['survey_group_pri'] = $_POST['assigned'];
1276
                            $extraParams['survey_group_sec1'] = 0;
1277
                            $extraParams['survey_group_sec2'] = 0;
1278
                        } elseif (2 == $_POST['choose']) {
1279
                            $extraParams['survey_group_pri'] = 0;
1280
                            $extraParams['survey_group_sec1'] = $_POST['assigned1'];
1281
                            $extraParams['survey_group_sec2'] = $_POST['assigned2'];
1282
                        }
1283
                    }
1284
1285
                    $maxScore = isset($form_content['maximum_score']) ? $form_content['maximum_score'] : null;
1286
                    $questionComment = isset($form_content['question_comment'])
1287
                        ? $form_content['question_comment']
1288
                        : null;
1289
1290
                    // Adding the question to the survey_question table
1291
                    $params = [
1292
                        'survey_question' => $form_content['question'],
1293
                        'survey_question_comment' => $questionComment,
1294
                        'display' => $form_content['horizontalvertical'],
1295
                    ];
1296
1297
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1298
                        $params['is_required'] = isset($form_content['is_required']);
1299
                    }
1300
1301
                    if (api_get_configuration_value('survey_question_dependency')) {
1302
                        $params['parent_id'] = 0;
1303
                        $params['parent_option_id'] = 0;
1304
                        if (isset($form_content['parent_id']) &&
1305
                            isset($form_content['parent_option_id']) &&
1306
                            !empty($form_content['parent_id']) &&
1307
                            !empty($form_content['parent_option_id'])
1308
                        ) {
1309
                            $params['parent_id'] = $form_content['parent_id'];
1310
                            $params['parent_option_id'] = $form_content['parent_option_id'];
1311
                        }
1312
                    }
1313
1314
                    $params = array_merge($params, $extraParams);
1315
                    Database::update(
1316
                        $tbl_survey_question,
1317
                        $params,
1318
                        [
1319
                            'c_id = ? AND question_id = ?' => [
1320
                                $course_id,
1321
                                $form_content['question_id'],
1322
                            ],
1323
                        ]
1324
                    );
1325
                    $return_message = 'QuestionUpdated';
1326
                }
1327
1328
                if (!empty($form_content['survey_id'])) {
1329
                    //Updating survey
1330
                    api_item_property_update(
0 ignored issues
show
Bug introduced by
The function api_item_property_update was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1330
                    /** @scrutinizer ignore-call */ 
1331
                    api_item_property_update(
Loading history...
1331
                        api_get_course_info(),
1332
                        TOOL_SURVEY,
1333
                        $form_content['survey_id'],
1334
                        'SurveyUpdated',
1335
                        api_get_user_id()
1336
                    );
1337
                }
1338
1339
                // Storing the options of the question
1340
                self::save_question_options($form_content, $survey_data, $dataFromDatabase);
1341
            } else {
1342
                $return_message = 'PleasFillAllAnswer';
1343
            }
1344
        } else {
1345
            $return_message = 'PleaseEnterAQuestion';
1346
        }
1347
1348
        if ($showMessage) {
1349
            if (!empty($return_message)) {
1350
                Display::addFlash(Display::return_message(get_lang($return_message)));
1351
            }
1352
        }
1353
1354
        return $return_message;
1355
    }
1356
1357
    /**
1358
     * This function saves the question in the shared database.
1359
     *
1360
     * @param array $form_content all the information of the form
1361
     * @param array $survey_data  all the information of the survey
1362
     *
1363
     * @author Patrick Cool <[email protected]>, Ghent University
1364
     *
1365
     * @version February 2007
1366
     *
1367
     * @return int
1368
     *
1369
     * @todo editing of a shared question
1370
     */
1371
    public function save_shared_question($form_content, $survey_data)
1372
    {
1373
        $_course = api_get_course_info();
1374
1375
        // Table definitions
1376
        $tbl_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1377
1378
        // Storing a new question
1379
        if ('' == $form_content['shared_question_id'] ||
1380
            !is_numeric($form_content['shared_question_id'])
1381
        ) {
1382
            // Finding the max sort order of the questions in the given survey
1383
            $sql = "SELECT max(sort) AS max_sort FROM $tbl_survey_question
1384
                    WHERE survey_id='".intval($survey_data['survey_share'])."'
1385
                    AND code='".Database::escape_string($_course['id'])."'";
1386
            $result = Database::query($sql);
1387
            $row = Database::fetch_array($result, 'ASSOC');
1388
            $max_sort = $row['max_sort'];
1389
1390
            // Adding the question to the survey_question table
1391
            $sql = "INSERT INTO $tbl_survey_question (survey_id, survey_question, survey_question_comment, type, display, sort, code) VALUES (
1392
                    '".Database::escape_string($survey_data['survey_share'])."',
1393
                    '".Database::escape_string($form_content['question'])."',
1394
                    '".Database::escape_string($form_content['question_comment'])."',
1395
                    '".Database::escape_string($form_content['type'])."',
1396
                    '".Database::escape_string($form_content['horizontalvertical'])."',
1397
                    '".Database::escape_string($max_sort + 1)."',
1398
                    '".Database::escape_string($_course['id'])."')";
1399
            Database::query($sql);
1400
            $shared_question_id = Database::insert_id();
1401
        } else {
1402
            // Updating an existing question
1403
            // adding the question to the survey_question table
1404
            $sql = "UPDATE $tbl_survey_question SET
1405
                        survey_question = '".Database::escape_string($form_content['question'])."',
1406
                        survey_question_comment = '".Database::escape_string($form_content['question_comment'])."',
1407
                        display = '".Database::escape_string($form_content['horizontalvertical'])."'
1408
                    WHERE
1409
                        question_id = '".intval($form_content['shared_question_id'])."' AND
1410
                        code = '".Database::escape_string($_course['id'])."'";
1411
            Database::query($sql);
1412
            $shared_question_id = $form_content['shared_question_id'];
1413
        }
1414
1415
        return $shared_question_id;
1416
    }
1417
1418
    /**
1419
     * This functions moves a question of a survey up or down.
1420
     *
1421
     * @param string $direction
1422
     * @param int    $survey_question_id
1423
     * @param int    $survey_id
1424
     *
1425
     * @author Patrick Cool <[email protected]>, Ghent University
1426
     *
1427
     * @version January 2007
1428
     */
1429
    public static function move_survey_question(
1430
        $direction,
1431
        $survey_question_id,
1432
        $survey_id
1433
    ) {
1434
        // Table definition
1435
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1436
        $course_id = api_get_course_int_id();
1437
1438
        if ('moveup' == $direction) {
1439
            $sort = 'DESC';
1440
        }
1441
        if ('movedown' == $direction) {
1442
            $sort = 'ASC';
1443
        }
1444
1445
        $survey_id = (int) $survey_id;
1446
1447
        // Finding the two questions that needs to be swapped
1448
        $sql = "SELECT * FROM $table_survey_question
1449
		        WHERE c_id = $course_id AND survey_id='".$survey_id."'
1450
		        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...
1451
        $result = Database::query($sql);
1452
        $found = false;
1453
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1454
            if ($found) {
1455
                $question_id_two = $row['question_id'];
1456
                $question_sort_two = $row['sort'];
1457
                $found = false;
1458
            }
1459
            if ($row['question_id'] == $survey_question_id) {
1460
                $found = true;
1461
                $question_id_one = $row['question_id'];
1462
                $question_sort_one = $row['sort'];
1463
            }
1464
        }
1465
1466
        $sql = "UPDATE $table_survey_question
1467
                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...
1468
		        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...
1469
        Database::query($sql);
1470
1471
        $sql = "UPDATE $table_survey_question
1472
                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...
1473
		        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...
1474
        Database::query($sql);
1475
    }
1476
1477
    /**
1478
     * This function deletes all the questions of a given survey
1479
     * This function is normally only called when a survey is deleted.
1480
     *
1481
     * @param int $survey_id the id of the survey that has to be deleted
1482
     *
1483
     * @return bool
1484
     *
1485
     * @author Patrick Cool <[email protected]>, Ghent University
1486
     *
1487
     * @version January 2007
1488
     */
1489
    public static function delete_all_survey_questions($survey_id, $shared = false)
1490
    {
1491
        $course_id = api_get_course_int_id();
1492
        $survey_id = (int) $survey_id;
1493
1494
        // Table definitions
1495
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1496
        $course_condition = " c_id = $course_id AND ";
1497
        if ($shared) {
1498
            $course_condition = '';
1499
            $table_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1500
        }
1501
1502
        $sql = "DELETE FROM $table_survey_question
1503
		        WHERE $course_condition survey_id = '".$survey_id."'";
1504
1505
        // Deleting the survey questions
1506
        Database::query($sql);
1507
1508
        // Deleting all the options of the questions of the survey
1509
        self::delete_all_survey_questions_options($survey_id, $shared);
1510
1511
        // Deleting all the answers on this survey
1512
        self::delete_all_survey_answers($survey_id);
1513
1514
        return true;
1515
    }
1516
1517
    /**
1518
     * This function deletes a survey question and all its options.
1519
     *
1520
     * @param int  $survey_id   the id of the survey
1521
     * @param int  $question_id the id of the question
1522
     * @param bool $shared
1523
     *
1524
     * @return mixed False on error, true if the question could be deleted
1525
     *
1526
     * @todo also delete the answers to this question
1527
     *
1528
     * @author Patrick Cool <[email protected]>, Ghent University
1529
     *
1530
     * @version March 2007
1531
     */
1532
    public static function delete_survey_question($survey_id, $question_id, $shared = false)
1533
    {
1534
        $survey_id = (int) $survey_id;
1535
        $question_id = (int) $question_id;
1536
        $course_id = api_get_course_int_id();
1537
1538
        if ($shared) {
1539
            self::delete_shared_survey_question($survey_id, $question_id);
1540
        }
1541
1542
        // Table definitions
1543
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1544
        // Deleting the survey questions
1545
        $sql = "DELETE FROM $table
1546
		        WHERE
1547
		            c_id = $course_id AND
1548
		            survey_id = $survey_id AND
1549
		            question_id = $question_id";
1550
        $result = Database::query($sql);
1551
        if (false == $result) {
1552
            return false;
1553
        }
1554
1555
        self::delete_survey_question_option($survey_id, $question_id, $shared);
1556
        // Deleting the options of the question of the survey
1557
        return true;
1558
    }
1559
1560
    /**
1561
     * This function deletes a shared survey question from the main database and all its options.
1562
     *
1563
     * @param int $question_id the id of the question
1564
     *
1565
     * @todo delete all the options of this question
1566
     *
1567
     * @author Patrick Cool <[email protected]>, Ghent University
1568
     *
1569
     * @version March 2007
1570
     */
1571
    public static function delete_shared_survey_question($survey_id, $question_id)
1572
    {
1573
        // Table definitions
1574
        $table_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
1575
        $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1576
1577
        // First we have to get the shared_question_id
1578
        $question_data = self::get_question($question_id);
1579
1580
        // Deleting the survey questions
1581
        $sql = "DELETE FROM $table_survey_question
1582
		        WHERE question_id='".intval($question_data['shared_question_id'])."'";
1583
        Database::query($sql);
1584
1585
        // Deleting the options of the question of the survey question
1586
        $sql = "DELETE FROM $table_survey_question_option
1587
		        WHERE question_id='".intval($question_data['shared_question_id'])."'";
1588
        Database::query($sql);
1589
    }
1590
1591
    /**
1592
     * This function stores the options of the questions in the table.
1593
     *
1594
     * @param array $form_content
1595
     *
1596
     * @author Patrick Cool <[email protected]>, Ghent University
1597
     *
1598
     * @version January 2007
1599
     *
1600
     * @todo writing the update statement when editing a question
1601
     */
1602
    public static function save_question_options($form_content, $survey_data, $dataFromDatabase = [])
1603
    {
1604
        $course_id = api_get_course_int_id();
1605
        $type = $form_content['type'];
1606
1607
        // A percentage question type has options 1 -> 100
1608
        if ('percentage' === $type) {
1609
            for ($i = 1; $i < 101; $i++) {
1610
                $form_content['answers'][] = $i;
1611
            }
1612
        }
1613
1614
        if (is_numeric($survey_data['survey_share']) && 0 != $survey_data['survey_share']) {
1615
            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

1615
            self::/** @scrutinizer ignore-call */ 
1616
                  save_shared_question_options($form_content, $survey_data);
Loading history...
1616
        }
1617
1618
        // Table definition
1619
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1620
1621
        // We are editing a question so we first have to remove all the existing options from the database
1622
        $optionsToDelete = [];
1623
        if (isset($dataFromDatabase['answer_data'])) {
1624
            foreach ($dataFromDatabase['answer_data'] as $data) {
1625
                if ('other' === $data['data'] && 'multiplechoiceother' === $type) {
1626
                    continue;
1627
                }
1628
1629
                if (!in_array($data['iid'], $form_content['answersid'])) {
1630
                    $optionsToDelete[] = $data['iid'];
1631
                }
1632
            }
1633
        }
1634
1635
        if (!empty($optionsToDelete)) {
1636
            foreach ($optionsToDelete as $iid) {
1637
                $iid = (int) $iid;
1638
                $sql = "DELETE FROM $table
1639
			            WHERE
1640
			                iid = $iid AND
1641
			                c_id = $course_id AND
1642
                            question_id = '".intval($form_content['question_id'])."'
1643
                            ";
1644
                Database::query($sql);
1645
            }
1646
        }
1647
1648
        $counter = 1;
1649
        if (isset($form_content['answers']) && is_array($form_content['answers'])) {
1650
            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...
1651
                $values = isset($form_content['values']) ? $form_content['values'][$i] : '';
1652
                $answerId = 0;
1653
                if (isset($form_content['answersid']) && isset($form_content['answersid'][$i])) {
1654
                    $answerId = $form_content['answersid'][$i];
1655
                }
1656
                if (empty($answerId)) {
1657
                    $params = [
1658
                        'c_id' => $course_id,
1659
                        'question_id' => $form_content['question_id'],
1660
                        'survey_id' => $form_content['survey_id'],
1661
                        'option_text' => $form_content['answers'][$i],
1662
                        'value' => $values,
1663
                        'sort' => $counter,
1664
                    ];
1665
                    $insertId = Database::insert($table, $params);
1666
                    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...
1667
                        $sql = "UPDATE $table
1668
                                SET question_option_id = $insertId
1669
                                WHERE iid = $insertId";
1670
                        Database::query($sql);
1671
                        $counter++;
1672
                    }
1673
                } else {
1674
                    $params = [
1675
                        'option_text' => $form_content['answers'][$i],
1676
                        'value' => $values,
1677
                        'sort' => $counter,
1678
                    ];
1679
                    Database::update($table, $params, ['iid = ?' => [$answerId]]);
1680
                    $counter++;
1681
                }
1682
            }
1683
        }
1684
1685
        if ('multiplechoiceother' === $type) {
1686
            if (empty($dataFromDatabase['answer_data'])) {
1687
                $params = [
1688
                    'c_id' => $course_id,
1689
                    'question_id' => $form_content['question_id'],
1690
                    'survey_id' => $form_content['survey_id'],
1691
                    'option_text' => 'other',
1692
                    'value' => 0,
1693
                    'sort' => $counter,
1694
                ];
1695
                $insertId = Database::insert($table, $params);
1696
                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...
1697
                    $sql = "UPDATE $table
1698
                            SET question_option_id = $insertId
1699
                            WHERE iid = $insertId";
1700
                    Database::query($sql);
1701
                }
1702
            } else {
1703
                $params = [
1704
                    'option_text' => 'other',
1705
                    'value' => 0,
1706
                    'sort' => $counter,
1707
                ];
1708
                Database::update(
1709
                    $table,
1710
                    $params,
1711
                    [
1712
                        'c_id = ? AND question_id = ? AND survey_id = ? AND option_text = ?' => [
1713
                            $course_id,
1714
                            $form_content['question_id'],
1715
                            $form_content['survey_id'],
1716
                            'other',
1717
                        ],
1718
                    ]
1719
                );
1720
            }
1721
        }
1722
    }
1723
1724
    /**
1725
     * This function stores the options of the questions in the shared table.
1726
     *
1727
     * @param array $form_content
1728
     *
1729
     * @author Patrick Cool <[email protected]>, Ghent University
1730
     *
1731
     * @version February 2007
1732
     *
1733
     * @todo writing the update statement when editing a question
1734
     */
1735
    public function save_shared_question_options($form_content, $survey_data)
1736
    {
1737
        if (is_array($form_content) && is_array($form_content['answers'])) {
1738
            // Table definition
1739
            $table = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1740
1741
            // We are editing a question so we first have to remove all the existing options from the database
1742
            $sql = "DELETE FROM $table
1743
                    WHERE question_id = '".Database::escape_string($form_content['shared_question_id'])."'";
1744
            Database::query($sql);
1745
1746
            $counter = 1;
1747
            foreach ($form_content['answers'] as &$answer) {
1748
                $params = [
1749
                    'question_id' => $form_content['shared_question_id'],
1750
                    'survey_id' => $survey_data['is_shared'],
1751
                    'option_text' => $answer,
1752
                    'sort' => $counter,
1753
                ];
1754
                Database::insert($table, $params);
1755
1756
                $counter++;
1757
            }
1758
        }
1759
    }
1760
1761
    /**
1762
     * This function deletes all the options of the questions of a given survey
1763
     * This function is normally only called when a survey is deleted.
1764
     *
1765
     * @param int $survey_id the id of the survey that has to be deleted
1766
     *
1767
     * @return true
1768
     *
1769
     * @author Patrick Cool <[email protected]>, Ghent University
1770
     *
1771
     * @version January 2007
1772
     */
1773
    public static function delete_all_survey_questions_options($survey_id, $shared = false)
1774
    {
1775
        // Table definitions
1776
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1777
        $course_id = api_get_course_int_id();
1778
        $course_condition = " c_id = $course_id AND ";
1779
        if ($shared) {
1780
            $course_condition = '';
1781
            $table_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1782
        }
1783
1784
        $sql = "DELETE FROM $table_survey_question_option
1785
                WHERE $course_condition survey_id='".intval($survey_id)."'";
1786
1787
        // Deleting the options of the survey questions
1788
        Database::query($sql);
1789
1790
        return true;
1791
    }
1792
1793
    /**
1794
     * This function deletes the options of a given question.
1795
     *
1796
     * @param int  $survey_id
1797
     * @param int  $question_id
1798
     * @param bool $shared
1799
     *
1800
     * @return bool
1801
     *
1802
     * @author Patrick Cool <[email protected]>, Ghent University
1803
     * @author Julio Montoya
1804
     *
1805
     * @version March 2007
1806
     */
1807
    public static function delete_survey_question_option(
1808
        $survey_id,
1809
        $question_id,
1810
        $shared = false
1811
    ) {
1812
        $course_id = api_get_course_int_id();
1813
        $course_condition = " c_id = $course_id AND ";
1814
1815
        // Table definitions
1816
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1817
        if ($shared) {
1818
            $course_condition = '';
1819
            $table = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
1820
        }
1821
1822
        // Deleting the options of the survey questions
1823
        $sql = "DELETE FROM $table
1824
		        WHERE
1825
		            $course_condition survey_id='".intval($survey_id)."' AND
1826
		            question_id='".intval($question_id)."'";
1827
        Database::query($sql);
1828
1829
        return true;
1830
    }
1831
1832
    /**
1833
     * SURVEY ANSWERS FUNCTIONS.
1834
     */
1835
1836
    /**
1837
     * This function deletes all the answers anyone has given on this survey
1838
     * This function is normally only called when a survey is deleted.
1839
     *
1840
     * @param $survey_id the id of the survey that has to be deleted
1841
     *
1842
     * @return true
1843
     *
1844
     * @todo write the function
1845
     *
1846
     * @author Patrick Cool <[email protected]>, Ghent University
1847
     *
1848
     * @version January 2007,december 2008
1849
     */
1850
    public static function delete_all_survey_answers($survey_id)
1851
    {
1852
        $course_id = api_get_course_int_id();
1853
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1854
        $survey_id = (int) $survey_id;
1855
        $sql = "DELETE FROM $table
1856
                WHERE c_id = $course_id AND survey_id = $survey_id";
1857
        Database::query($sql);
1858
1859
        return true;
1860
    }
1861
1862
    /**
1863
     * @param int $user_id
1864
     * @param int $survey_id
1865
     * @param int $course_id
1866
     *
1867
     * @return bool
1868
     */
1869
    public static function is_user_filled_survey($user_id, $survey_id, $course_id)
1870
    {
1871
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1872
        $user_id = (int) $user_id;
1873
        $course_id = (int) $course_id;
1874
        $survey_id = (int) $survey_id;
1875
1876
        $sql = "SELECT DISTINCT user
1877
                FROM $table
1878
                WHERE
1879
                    c_id		= $course_id AND
1880
                    user		= $user_id AND
1881
                    survey_id	= $survey_id";
1882
        $result = Database::query($sql);
1883
        if (Database::num_rows($result)) {
1884
            return true;
1885
        }
1886
1887
        return false;
1888
    }
1889
1890
    /**
1891
     * This function gets all the persons who have filled the survey.
1892
     *
1893
     * @param int $survey_id
1894
     *
1895
     * @return array
1896
     *
1897
     * @author Patrick Cool <[email protected]>, Ghent University
1898
     *
1899
     * @version February 2007
1900
     */
1901
    public static function get_people_who_filled_survey(
1902
        $survey_id,
1903
        $all_user_info = false,
1904
        $course_id = null
1905
    ) {
1906
        // Database table definition
1907
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1908
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1909
1910
        // Variable initialisation
1911
        $return = [];
1912
1913
        if (empty($course_id)) {
1914
            $course_id = api_get_course_int_id();
1915
        } else {
1916
            $course_id = (int) $course_id;
1917
        }
1918
1919
        $survey_id = (int) $survey_id;
1920
1921
        if ($all_user_info) {
1922
            $order_clause = api_sort_by_first_name()
1923
                ? ' ORDER BY user.firstname, user.lastname'
1924
                : ' ORDER BY user.lastname, user.firstname';
1925
            $sql = "SELECT DISTINCT
1926
			            answered_user.user as invited_user,
1927
			            user.firstname,
1928
			            user.lastname,
1929
			            user.id as user_id
1930
                    FROM $table_survey_answer answered_user
1931
                    LEFT JOIN $table_user as user ON answered_user.user = user.id
1932
                    WHERE
1933
                        answered_user.c_id = $course_id AND
1934
                        survey_id= '".$survey_id."' ".
1935
                $order_clause;
1936
        } else {
1937
            $sql = "SELECT DISTINCT user FROM $table_survey_answer
1938
			        WHERE c_id = $course_id AND survey_id= '".$survey_id."'  ";
1939
1940
            if (api_get_configuration_value('survey_anonymous_show_answered')) {
1941
                $tblInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
1942
                $tblSurvey = Database::get_course_table(TABLE_SURVEY);
1943
1944
                $sql = "SELECT i.user FROM $tblInvitation i
1945
                    INNER JOIN $tblSurvey s
1946
                    ON i.survey_code = s.code
1947
                        AND i.c_id = s.c_id
1948
                        AND i.session_id = s.session_id
1949
                    WHERE i.answered IS TRUE AND s.iid = $survey_id";
1950
            }
1951
        }
1952
1953
        $res = Database::query($sql);
1954
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1955
            if ($all_user_info) {
1956
                $userInfo = api_get_user_info($row['user_id']);
1957
                $row['user_info'] = $userInfo;
1958
                $return[] = $row;
1959
            } else {
1960
                $return[] = $row['user'];
1961
            }
1962
        }
1963
1964
        return $return;
1965
    }
1966
1967
    /**
1968
     * @return bool
1969
     */
1970
    public static function survey_generation_hash_available()
1971
    {
1972
        if (extension_loaded('mcrypt')) {
1973
            return true;
1974
        }
1975
1976
        return false;
1977
    }
1978
1979
    /**
1980
     * @param int $survey_id
1981
     * @param int $course_id
1982
     * @param int $session_id
1983
     * @param int $group_id
1984
     *
1985
     * @return string
1986
     */
1987
    public static function generate_survey_hash($survey_id, $course_id, $session_id, $group_id)
1988
    {
1989
        return hash('sha512', api_get_security_key().'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id);
1990
    }
1991
1992
    /**
1993
     * @param int    $survey_id
1994
     * @param int    $course_id
1995
     * @param int    $session_id
1996
     * @param int    $group_id
1997
     * @param string $hash
1998
     *
1999
     * @return bool
2000
     */
2001
    public static function validate_survey_hash($survey_id, $course_id, $session_id, $group_id, $hash)
2002
    {
2003
        $generatedHash = self::generate_survey_hash($survey_id, $course_id, $session_id, $group_id);
2004
        if ($generatedHash == $hash) {
2005
            return true;
2006
        }
2007
2008
        return false;
2009
    }
2010
2011
    /**
2012
     * @param int $survey_id
2013
     * @param int $course_id
2014
     * @param int $session_id
2015
     * @param int $group_id
2016
     *
2017
     * @return string
2018
     */
2019
    public static function generate_survey_link(
2020
        $survey_id,
2021
        $course_id,
2022
        $session_id,
2023
        $group_id
2024
    ) {
2025
        $code = self::generate_survey_hash(
2026
            $survey_id,
2027
            $course_id,
2028
            $session_id,
2029
            $group_id
2030
        );
2031
2032
        return api_get_path(WEB_CODE_PATH).'survey/link.php?h='.$code.'&i='.$survey_id.'&c='.intval($course_id).'&s='
2033
            .intval($session_id).'&g='.$group_id;
2034
    }
2035
2036
    /**
2037
     * Check if the current user has mandatory surveys no-answered
2038
     * and redirect to fill the first found survey.
2039
     */
2040
    public static function protectByMandatory()
2041
    {
2042
        if (false !== strpos($_SERVER['SCRIPT_NAME'], 'fillsurvey.php')) {
2043
            return;
2044
        }
2045
2046
        $userId = api_get_user_id();
2047
        $courseId = api_get_course_int_id();
2048
        $sessionId = api_get_session_id();
2049
2050
        if (!$userId) {
2051
            return;
2052
        }
2053
2054
        if (!$courseId) {
2055
            return;
2056
        }
2057
2058
        try {
2059
            /** @var CSurveyInvitation $invitation */
2060
            $invitation = Database::getManager()
2061
                ->createQuery("
2062
                    SELECT i FROM ChamiloCourseBundle:CSurveyInvitation i
2063
                    INNER JOIN ChamiloCourseBundle:CSurvey s
2064
                        WITH (s.code = i.surveyCode AND s.cId = i.cId AND s.sessionId = i.sessionId)
2065
                    INNER JOIN ChamiloCoreBundle:ExtraFieldValues efv WITH efv.itemId = s.iid
2066
                    INNER JOIN ChamiloCoreBundle:ExtraField ef WITH efv.field = ef.id
2067
                    WHERE
2068
                        i.answered = 0 AND
2069
                        i.cId = :course AND
2070
                        i.user = :user AND
2071
                        i.sessionId = :session AND
2072
                        :now BETWEEN s.availFrom AND s.availTill AND
2073
                        ef.variable = :variable AND
2074
                        efv.value = 1 AND
2075
                        s.surveyType != 3
2076
                    ORDER BY s.availTill ASC
2077
                ")
2078
                ->setMaxResults(1)
2079
                ->setParameters([
2080
                    'course' => $courseId,
2081
                    'user' => $userId,
2082
                    'session' => $sessionId,
2083
                    'now' => new DateTime('UTC', new DateTimeZone('UTC')),
2084
                    'variable' => 'is_mandatory',
2085
                ])
2086
                ->getSingleResult();
2087
        } catch (Exception $e) {
2088
            $invitation = null;
2089
        }
2090
2091
        if (!$invitation) {
2092
            return;
2093
        }
2094
2095
        Display::addFlash(
2096
            Display::return_message(get_lang('A mandatory survey is waiting your answer. To enter the course, you must first complete the survey.'), 'warning')
2097
        );
2098
2099
        $url = SurveyUtil::generateFillSurveyLink(
2100
            $invitation->getInvitationCode(),
2101
            api_get_course_info(),
2102
            api_get_session_id()
2103
        );
2104
2105
        header('Location: '.$url);
2106
        exit;
2107
    }
2108
2109
    /**
2110
     * This function empty surveys (invitations and answers).
2111
     *
2112
     * @param int $surveyId id of the survey to empty
2113
     *
2114
     * @return bool
2115
     */
2116
    public static function emptySurveyFromId($surveyId)
2117
    {
2118
        // Database table definitions
2119
        $surveyInvitationTable = Database:: get_course_table(TABLE_SURVEY_INVITATION);
2120
        $surveyAnswerTable = Database:: get_course_table(TABLE_SURVEY_ANSWER);
2121
        $surveyTable = Database:: get_course_table(TABLE_SURVEY);
2122
        $surveyId = (int) $surveyId;
2123
        $surveyData = self::get_survey($surveyId);
2124
        if (empty($surveyData)) {
2125
            return false;
2126
        }
2127
2128
        $surveyCode = $surveyData['survey_code'];
2129
        $courseId = (int) $surveyData['c_id'];
2130
        $sessionId = (int) $surveyData['session_id'];
2131
2132
        $sql = "DELETE FROM $surveyInvitationTable
2133
                WHERE session_id = $sessionId AND c_id = $courseId AND survey_code = '$surveyCode' ";
2134
        Database::query($sql);
2135
2136
        $sql = "DELETE FROM $surveyAnswerTable
2137
               WHERE survey_id = $surveyId AND c_id = $courseId ";
2138
        Database::query($sql);
2139
2140
        $sql = "UPDATE $surveyTable
2141
                SET invited = 0, answered = 0
2142
                WHERE survey_id = $surveyId AND c_id = $courseId AND session_id = $sessionId ";
2143
        Database::query($sql);
2144
2145
        return true;
2146
    }
2147
2148
    /**
2149
     * Copy survey specifying course ID and session ID where will be copied.
2150
     *
2151
     * @param int $surveyId
2152
     * @param int $targetCourseId  target course id
2153
     * @param int $targetSessionId target session id
2154
     *
2155
     * @return bool|int when fails or return the new survey id
2156
     */
2157
    public static function copySurveySession($surveyId, $targetCourseId, $targetSessionId)
2158
    {
2159
        // Database table definitions
2160
        $surveyTable = Database::get_course_table(TABLE_SURVEY);
2161
        $surveyQuestionGroupTable = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
2162
        $surveyQuestionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
2163
        $surveyOptionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2164
        $surveyId = (int) $surveyId;
2165
        $targetCourseId = (int) $targetCourseId;
2166
        $targetSessionId = (int) $targetSessionId;
2167
2168
        $surveyData = self::get_survey($surveyId, 0, '', true);
2169
        if (empty($surveyData) || empty($targetCourseId)) {
2170
            return false;
2171
        }
2172
2173
        $originalCourseId = $surveyData['c_id'];
2174
        $originalSessionId = $surveyData['session_id'];
2175
2176
        $surveyData['code'] = self::generate_unique_code($surveyData['code']);
2177
        $surveyData['c_id'] = $targetCourseId;
2178
        $surveyData['session_id'] = $targetSessionId;
2179
        // Add a "Copy" suffix if copied inside the same course
2180
        if ($targetCourseId == $originalCourseId) {
2181
            $surveyData['title'] = $surveyData['title'].' '.get_lang('Copy');
2182
        }
2183
        unset($surveyData['iid']);
2184
        unset($surveyData['id']);
2185
2186
        $newSurveyId = Database::insert($surveyTable, $surveyData);
2187
2188
        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...
2189
            $sql = "UPDATE $surveyTable SET survey_id = $newSurveyId
2190
                    WHERE iid = $newSurveyId";
2191
            Database::query($sql);
2192
2193
            $sql = "SELECT * FROM $surveyQuestionGroupTable
2194
                    WHERE c_id = $originalCourseId AND survey_id = $surveyId";
2195
            $res = Database::query($sql);
2196
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2197
                $params = [
2198
                    'c_id' => $targetCourseId,
2199
                    'name' => $row['name'],
2200
                    'description' => $row['description'],
2201
                    'survey_id' => $newSurveyId,
2202
                ];
2203
                $insertId = Database::insert($surveyQuestionGroupTable, $params);
2204
                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...
2205
                    $sql = "UPDATE $surveyQuestionGroupTable SET id = iid WHERE iid = $insertId";
2206
                    Database::query($sql);
2207
                    $group_id[$row['id']] = $insertId;
2208
                }
2209
            }
2210
2211
            // Get questions
2212
            $sql = "SELECT * FROM $surveyQuestionTable
2213
                    WHERE c_id = $originalCourseId AND survey_id = $surveyId";
2214
            $res = Database::query($sql);
2215
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2216
                $params = [
2217
                    'c_id' => $targetCourseId,
2218
                    'survey_id' => $newSurveyId,
2219
                    'survey_question' => $row['survey_question'],
2220
                    'survey_question_comment' => $row['survey_question_comment'],
2221
                    'type' => $row['type'],
2222
                    'display' => $row['display'],
2223
                    'sort' => $row['sort'],
2224
                    'shared_question_id' => $row['shared_question_id'],
2225
                    'max_value' => $row['max_value'],
2226
                    'survey_group_pri' => $row['survey_group_pri'],
2227
                    'survey_group_sec1' => $row['survey_group_sec1'],
2228
                    'survey_group_sec2' => $row['survey_group_sec2'],
2229
                ];
2230
2231
                if (api_get_configuration_value('allow_required_survey_questions')) {
2232
                    if (isset($row['is_required'])) {
2233
                        $params['is_required'] = $row['is_required'];
2234
                    }
2235
                }
2236
2237
                $insertId = Database::insert($surveyQuestionTable, $params);
2238
                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...
2239
                    $sql = "UPDATE $surveyQuestionTable
2240
                            SET question_id = iid
2241
                            WHERE iid = $insertId";
2242
                    Database::query($sql);
2243
2244
                    $question_id[$row['question_id']] = $insertId;
2245
                }
2246
            }
2247
2248
            // Get questions options
2249
            $sql = "SELECT * FROM $surveyOptionsTable
2250
                    WHERE survey_id = $surveyId AND c_id = $originalCourseId";
2251
2252
            $res = Database::query($sql);
2253
            while ($row = Database::fetch_array($res, 'ASSOC')) {
2254
                $params = [
2255
                    'c_id' => $targetCourseId,
2256
                    '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...
2257
                    'survey_id' => $newSurveyId,
2258
                    'option_text' => $row['option_text'],
2259
                    'sort' => $row['sort'],
2260
                    'value' => $row['value'],
2261
                ];
2262
                $insertId = Database::insert($surveyOptionsTable, $params);
2263
                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...
2264
                    $sql = "UPDATE $surveyOptionsTable SET question_option_id = $insertId WHERE iid = $insertId";
2265
                    Database::query($sql);
2266
                }
2267
            }
2268
2269
            return $newSurveyId;
2270
        }
2271
2272
        return false;
2273
    }
2274
2275
    /**
2276
     * Copy/duplicate one question (into the same survey).
2277
     * Note: Relies on the question iid to find all necessary info.
2278
     *
2279
     * @param int $questionId
2280
     *
2281
     * @return int The new question's iid, or 0 on error
2282
     */
2283
    public static function copyQuestion($questionId)
2284
    {
2285
        if (empty($questionId)) {
2286
            return 0;
2287
        }
2288
        $questionId = (int) $questionId;
2289
        $questionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
2290
        $optionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2291
2292
        // Get questions
2293
        $sql = "SELECT * FROM $questionTable WHERE iid = $questionId";
2294
        $res = Database::query($sql);
2295
        if (false == $res) {
2296
            // Could not find this question
2297
            return 0;
2298
        }
2299
        $row = Database::fetch_array($res, 'ASSOC');
2300
        $params = [
2301
            'c_id' => $row['c_id'],
2302
            'survey_id' => $row['survey_id'],
2303
            'survey_question' => trim($row['survey_question']),
2304
            'survey_question_comment' => $row['survey_question_comment'],
2305
            'type' => $row['type'],
2306
            'display' => $row['display'],
2307
            'shared_question_id' => $row['shared_question_id'],
2308
            'max_value' => $row['max_value'],
2309
            'survey_group_pri' => $row['survey_group_pri'],
2310
            'survey_group_sec1' => $row['survey_group_sec1'],
2311
            'survey_group_sec2' => $row['survey_group_sec2'],
2312
        ];
2313
        if (api_get_configuration_value('allow_required_survey_questions')) {
2314
            if (isset($row['is_required'])) {
2315
                $params['is_required'] = $row['is_required'];
2316
            }
2317
        }
2318
        // Get question position
2319
        $sqlSort = "SELECT max(sort) as sort FROM $questionTable
2320
                    WHERE survey_id = ".$row['survey_id'];
2321
        $resSort = Database::query($sqlSort);
2322
        $rowSort = Database::fetch_assoc($resSort);
2323
        $params['sort'] = $rowSort['sort'] + 1;
2324
        // Insert the new question
2325
        $insertId = Database::insert($questionTable, $params);
2326
        if (false == $insertId) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $insertId of type false|integer against false; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
2327
            return 0;
2328
        }
2329
        // Normalize question_id with iid
2330
        $sql = "UPDATE $questionTable
2331
                SET question_id = iid
2332
                WHERE iid = $insertId";
2333
        Database::query($sql);
2334
2335
        // Get questions options
2336
        $sql = "SELECT * FROM $optionsTable WHERE question_id = $questionId";
2337
        $res = Database::query($sql);
2338
        while ($row = Database::fetch_assoc($res)) {
2339
            $params = [
2340
                'c_id' => $row['c_id'],
2341
                'question_id' => $insertId,
2342
                'survey_id' => $row['survey_id'],
2343
                'option_text' => $row['option_text'],
2344
                'sort' => $row['sort'],
2345
                'value' => $row['value'],
2346
            ];
2347
            $optionId = Database::insert($optionsTable, $params);
2348
            if ($optionId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $optionId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2349
                $sql = "UPDATE $optionsTable SET question_option_id = $optionId WHERE iid = $optionId";
2350
                Database::query($sql);
2351
            }
2352
        }
2353
2354
        return $insertId;
2355
    }
2356
2357
    /**
2358
     * @param array $surveyData
2359
     *
2360
     * @return bool
2361
     */
2362
    public static function removeMultiplicateQuestions($surveyData)
2363
    {
2364
        if (empty($surveyData)) {
2365
            return false;
2366
        }
2367
        $surveyId = $surveyData['survey_id'];
2368
        $courseId = $surveyData['c_id'];
2369
2370
        if (empty($surveyId) || empty($courseId)) {
2371
            return false;
2372
        }
2373
2374
        $questions = self::get_questions($surveyId);
2375
        foreach ($questions as $question) {
2376
            // Questions marked with "geneated" were created using the "multiplicate" feature.
2377
            if ('generated' === $question['survey_question_comment']) {
2378
                self::delete_survey_question($surveyId, $question['question_id']);
2379
            }
2380
        }
2381
    }
2382
2383
    /**
2384
     * @param array $surveyData
2385
     *
2386
     * @return bool
2387
     */
2388
    public static function multiplicateQuestions($surveyData)
2389
    {
2390
        if (empty($surveyData)) {
2391
            return false;
2392
        }
2393
        $surveyId = $surveyData['survey_id'];
2394
        $courseId = $surveyData['c_id'];
2395
2396
        if (empty($surveyId) || empty($courseId)) {
2397
            return false;
2398
        }
2399
2400
        $questions = self::get_questions($surveyId);
2401
2402
        if (empty($questions)) {
2403
            return false;
2404
        }
2405
2406
        $extraFieldValue = new ExtraFieldValue('survey');
2407
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
2408
        $groupId = null;
2409
        if ($groupData && !empty($groupData['value'])) {
2410
            $groupId = (int) $groupData['value'];
2411
        }
2412
2413
        if (null === $groupId) {
2414
        $obj = new UserGroup();
2415
        $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...
2416
        $classList = $obj->getUserGroupInCourse($options);
2417
2418
        $classToParse = [];
2419
        foreach ($classList as $class) {
2420
            $users = $obj->get_users_by_usergroup($class['id']);
2421
            if (empty($users)) {
2422
                continue;
2423
            }
2424
            $classToParse[] = [
2425
                'name' => $class['name'],
2426
                'users' => $users,
2427
            ];
2428
        }
2429
2430
            self::parseMultiplicateUserList($classToParse, $questions, $courseId, $surveyData, true);
2431
        } else {
2432
            $groupInfo = GroupManager::get_group_properties($groupId);
2433
            if (!empty($groupInfo)) {
2434
                $users = GroupManager::getStudents($groupInfo['iid'], true);
2435
                if (!empty($users)) {
2436
                    $users = array_column($users, 'id');
2437
                    self::parseMultiplicateUserList(
2438
                        [
2439
                        [
2440
                            'name' => $groupInfo['name'],
2441
                            'users' => $users,
2442
                        ],
2443
                        ],
2444
                        $questions,
2445
                        $courseId,
2446
                        $surveyData,
2447
                        false
2448
                    );
2449
                }
2450
            }
2451
        }
2452
2453
        return true;
2454
    }
2455
2456
    public static function parseMultiplicateUserList($itemList, $questions, $courseId, $surveyData, $addClassNewPage = false)
2457
    {
2458
        if (empty($itemList) || empty($questions)) {
2459
            return false;
2460
        }
2461
2462
        $surveyId = $surveyData['survey_id'];
2463
        $classTag = '{{class_name}}';
2464
        $studentTag = '{{student_full_name}}';
2465
        $classCounter = 0;
2466
2467
        $newQuestionList = [];
2468
        foreach ($questions as $question) {
2469
            $newQuestionList[$question['sort']] = $question;
2470
        }
2471
        ksort($newQuestionList);
2472
2473
        $order = api_get_configuration_value('survey_duplicate_order_by_name');
2474
        foreach ($itemList as $class) {
2475
            $className = $class['name'];
2476
            $users = $class['users'];
2477
            $userInfoList = [];
2478
            foreach ($users as $userId) {
2479
                $userInfoList[] = api_get_user_info($userId);
2480
            }
2481
2482
            if ($order) {
2483
                usort(
2484
                    $userInfoList,
2485
                    function ($a, $b) {
2486
                        return $a['lastname'] > $b['lastname'];
2487
                    }
2488
                );
2489
            }
2490
2491
            foreach ($newQuestionList as $question) {
2492
                $text = $question['question'];
2493
                if (false !== strpos($text, $classTag)) {
2494
                    $replacedText = str_replace($classTag, $className, $text);
2495
                    $values = [
2496
                        'c_id' => $courseId,
2497
                        'question_comment' => 'generated',
2498
                        'type' => $question['type'],
2499
                        'display' => $question['horizontalvertical'],
2500
                        'horizontalvertical' => $question['horizontalvertical'],
2501
                        'question' => $replacedText,
2502
                        'survey_id' => $surveyId,
2503
                        'question_id' => 0,
2504
                        'shared_question_id' => 0,
2505
                        'answers' => $question['answers'] ?? null,
2506
                    ];
2507
                    self::save_question($surveyData, $values, false);
2508
                    $classCounter++;
2509
                    continue;
2510
                }
2511
2512
                foreach ($userInfoList as $userInfo) {
2513
2514
                    if (false !== strpos($text, $studentTag)) {
2515
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
2516
                        $values = [
2517
                            'c_id' => $courseId,
2518
                            'question_comment' => 'generated',
2519
                            'type' => $question['type'],
2520
                            'display' => $question['horizontalvertical'],
2521
                            'maximum_score' => $question['maximum_score'],
2522
                            'question' => $replacedText,
2523
                            'survey_id' => $surveyId,
2524
                            'question_id' => 0,
2525
                            'shared_question_id' => 0,
2526
                        ];
2527
2528
                        $answers = [];
2529
                        if (!empty($question['answers'])) {
2530
                            foreach ($question['answers'] as $answer) {
2531
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
2532
                                $answers[] = $replacedText;
2533
                            }
2534
                        }
2535
                        $values['answers'] = $answers;
2536
                        self::save_question($surveyData, $values, false);
2537
                    }
2538
                }
2539
2540
                if ($addClassNewPage && $classCounter < count($itemList)) {
2541
                    // Add end page
2542
                    $values = [
2543
                        'c_id' => $courseId,
2544
                        'question_comment' => 'generated',
2545
                        'type' => 'pagebreak',
2546
                        'display' => 'horizontal',
2547
                        'question' => get_lang('Question for next class'),
2548
                        'survey_id' => $surveyId,
2549
                        'question_id' => 0,
2550
                        'shared_question_id' => 0,
2551
                    ];
2552
                    self::save_question($surveyData, $values, false);
2553
                }
2554
            }
2555
        }
2556
2557
        return true;
2558
    }
2559
2560
    public static function hasDependency($survey)
2561
    {
2562
        if (false === api_get_configuration_value('survey_question_dependency')) {
2563
            return false;
2564
        }
2565
2566
        if (empty($survey)) {
2567
            return false;
2568
        }
2569
2570
        if (!isset($survey['survey_id'])) {
2571
            return false;
2572
        }
2573
2574
        $courseId = (int) $survey['c_id'];
2575
        $surveyId = (int) $survey['survey_id'];
2576
2577
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
2578
2579
        $sql = "SELECT COUNT(iid) count FROM $table
2580
                WHERE
2581
                    c_id = $courseId AND
2582
                    survey_id = $surveyId AND
2583
                    parent_option_id <> 0
2584
                LIMIT 1
2585
                ";
2586
        $result = Database::query($sql);
2587
        $row = Database::fetch_array($result);
2588
2589
        if ($row) {
2590
            return $row['count'] > 0;
2591
        }
2592
2593
        return false;
2594
    }
2595
2596
    /**
2597
     * @param array $survey
2598
     *
2599
     * @return int
2600
     */
2601
    public static function getCountPages($survey)
2602
    {
2603
        if (empty($survey) || !isset($survey['iid'])) {
2604
            return 0;
2605
        }
2606
2607
        $courseId = (int) $survey['c_id'];
2608
        $surveyId = (int) $survey['survey_id'];
2609
2610
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
2611
2612
        // pagebreak
2613
        $sql = "SELECT COUNT(iid) FROM $table
2614
                WHERE
2615
                    survey_question NOT LIKE '%{{%' AND
2616
                    type = 'pagebreak' AND
2617
                    c_id = $courseId AND
2618
                    survey_id = $surveyId";
2619
        $result = Database::query($sql);
2620
        $numberPageBreaks = Database::result($result, 0, 0);
2621
2622
        // No pagebreak
2623
        $sql = "SELECT COUNT(iid) FROM $table
2624
                WHERE
2625
                    survey_question NOT LIKE '%{{%' AND
2626
                    type != 'pagebreak' AND
2627
                    c_id = $courseId AND
2628
                    survey_id = $surveyId";
2629
        $result = Database::query($sql);
2630
        $countOfQuestions = Database::result($result, 0, 0);
2631
2632
        if (1 == $survey['one_question_per_page']) {
2633
            if (!empty($countOfQuestions)) {
2634
                return $countOfQuestions;
2635
            }
2636
2637
            return 1;
2638
        }
2639
2640
        if (empty($numberPageBreaks)) {
2641
            return 1;
2642
        }
2643
2644
        return $numberPageBreaks + 1;
2645
    }
2646
2647
    /**
2648
     * Check whether this survey has ended. If so, display message and exit rhis script.
2649
     *
2650
     * @param array $surveyData Survey data
2651
     */
2652
    public static function checkTimeAvailability($surveyData)
2653
    {
2654
        if (empty($surveyData)) {
2655
            api_not_allowed(true);
2656
        }
2657
2658
        $allowSurveyAvailabilityDatetime = api_get_configuration_value('allow_survey_availability_datetime');
2659
        $utcZone = new DateTimeZone('UTC');
2660
        $startDate = new DateTime($surveyData['start_date'], $utcZone);
2661
        $endDate = new DateTime($surveyData['end_date'], $utcZone);
2662
        $currentDate = new DateTime('now', $utcZone);
2663
        if (!$allowSurveyAvailabilityDatetime) {
2664
            $currentDate->modify('today');
2665
        }
2666
        if ($currentDate < $startDate) {
2667
            api_not_allowed(
2668
                true,
2669
                Display:: return_message(
2670
                    get_lang('This survey is not yet available. Please try again later. Thank you.'),
2671
                    'warning',
2672
                    false
2673
                )
2674
            );
2675
        }
2676
2677
        if ($currentDate > $endDate) {
2678
            api_not_allowed(
2679
                true,
2680
                Display:: return_message(
2681
                    get_lang('Sorry, this survey is not available anymore. Thank you for trying.'),
2682
                    'warning',
2683
                    false
2684
                )
2685
            );
2686
        }
2687
    }
2688
2689
    /**
2690
     * @param int    $userId
2691
     * @param string $surveyCode
2692
     * @param int    $courseId
2693
     * @param int    $sessionId
2694
     * @param int    $groupId
2695
     *
2696
     * @return array|CSurveyInvitation[]
2697
     */
2698
    public static function getUserInvitationsForSurveyInCourse(
2699
        $userId,
2700
        $surveyCode,
2701
        $courseId,
2702
        $sessionId = 0,
2703
        $groupId = 0
2704
    ) {
2705
        $invitationRepo = Database::getManager()->getRepository('ChamiloCourseBundle:CSurveyInvitation');
2706
2707
        return $invitationRepo->findBy(
2708
            [
2709
                'user' => $userId,
2710
                'cId' => $courseId,
2711
                'sessionId' => $sessionId,
2712
                'groupId' => $groupId,
2713
                'surveyCode' => $surveyCode,
2714
            ],
2715
            ['invitationDate' => 'DESC']
2716
        );
2717
    }
2718
2719
    /**
2720
     * @param array $userInfo
2721
     * @param int   $answered (1 = answered 0 = not answered)
2722
     *
2723
     * @return string
2724
     */
2725
    public static function surveyReport($userInfo, $answered = 0)
2726
    {
2727
        $userId = isset($userInfo['user_id']) ? (int) $userInfo['user_id'] : 0;
2728
        $answered = (int) $answered;
2729
2730
        if (empty($userId)) {
2731
            return '';
2732
        }
2733
2734
        $em = Database::getManager();
2735
        $repo = $em->getRepository('ChamiloCourseBundle:CSurveyInvitation');
2736
        $repoSurvey = $em->getRepository('ChamiloCourseBundle:CSurvey');
2737
        $invitations = $repo->findBy(['user' => $userId, 'answered' => $answered]);
2738
        $mainUrl = api_get_path(WEB_CODE_PATH).'survey/survey.php?';
2739
        $content = '';
2740
2741
        if (empty($answered)) {
2742
            $content .= Display::page_subheader(get_lang('Unanswered'));
2743
        } else {
2744
            $content .= Display::page_subheader(get_lang('Answered'));
2745
        }
2746
2747
        if (!empty($invitations)) {
2748
            $table = new HTML_Table(['class' => 'table']);
2749
            $table->setHeaderContents(0, 0, get_lang('Survey name'));
2750
            $table->setHeaderContents(0, 1, get_lang('Course'));
2751
2752
            if (empty($answered)) {
2753
                $table->setHeaderContents(0, 2, get_lang('Survey').' - '.get_lang('End Date'));
2754
            }
2755
2756
            // Not answered
2757
            /** @var CSurveyInvitation $invitation */
2758
            $row = 1;
2759
            foreach ($invitations as $invitation) {
2760
                $courseId = $invitation->getCId();
2761
                $courseInfo = api_get_course_info_by_id($courseId);
2762
2763
                $courseCode = $courseInfo['code'];
2764
                if (empty($courseInfo)) {
2765
                    continue;
2766
                }
2767
                $sessionId = $invitation->getSessionId();
2768
2769
                if (!empty($answered)) {
2770
                    // check if user is subscribed to the course/session
2771
                    if (empty($sessionId)) {
2772
                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode);
2773
                    } else {
2774
                        $subscribe = CourseManager::is_user_subscribed_in_course(
2775
                            $userId,
2776
                            $courseCode,
2777
                            true,
2778
                            $sessionId
2779
                        );
2780
                    }
2781
2782
                    // User is not subscribe skip!
2783
                    if (empty($subscribe)) {
2784
                        continue;
2785
                    }
2786
                }
2787
2788
                $surveyCode = $invitation->getSurveyCode();
2789
2790
                $survey = $repoSurvey->findOneBy([
2791
                    'cId' => $courseId,
2792
                    'sessionId' => $sessionId,
2793
                    'code' => $surveyCode,
2794
                ]);
2795
2796
                if (empty($survey)) {
2797
                    continue;
2798
                }
2799
2800
                $url = $mainUrl.'survey_id='.$survey->getSurveyId().'&cid='.$courseId.'&sid='.$sessionId;
2801
                $title = $survey->getTitle();
2802
                $title = Display::url($title, $url);
2803
2804
                if (!empty($sessionId)) {
2805
                    $sessionInfo = api_get_session_info($sessionId);
2806
                    $courseInfo['name'] .= ' ('.$sessionInfo['name'].')';
2807
                }
2808
2809
                $surveyData = self::get_survey($survey->getSurveyId(), 0, $courseCode);
2810
                $table->setCellContents($row, 0, $title);
2811
                $table->setCellContents($row, 1, $courseInfo['name']);
2812
2813
                if (empty($answered)) {
2814
                    $table->setHeaderContents(
2815
                        $row,
2816
                        2,
2817
                        api_get_local_time(
2818
                            $survey->getAvailTill(),
2819
                            null,
2820
                            null,
2821
                            true,
2822
                            false
2823
                        )
2824
                    );
2825
                }
2826
2827
                if (!empty($answered) && 0 == $surveyData['anonymous']) {
2828
                    $answers = SurveyUtil::displayCompleteReport(
2829
                        $surveyData,
2830
                        $userId,
2831
                        false,
2832
                        false,
2833
                        false
2834
                    );
2835
                    $table->setCellContents(++$row, 0, $answers);
2836
                    $table->setCellContents(++$row, 1, '');
2837
                }
2838
2839
                $row++;
2840
            }
2841
            $content .= $table->toHtml();
2842
        } else {
2843
            $content .= Display::return_message(get_lang('No data available'));
2844
        }
2845
2846
        return $content;
2847
    }
2848
2849
    public static function sendToTutors($surveyId)
2850
    {
2851
        $survey = Database::getManager()->getRepository('ChamiloCourseBundle:CSurvey')->find($surveyId);
2852
        if (null === $survey) {
2853
            return false;
2854
        }
2855
2856
        $extraFieldValue = new ExtraFieldValue('survey');
2857
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
2858
        if ($groupData && !empty($groupData['value'])) {
2859
            $groupInfo = GroupManager::get_group_properties($groupData['value']);
2860
            if ($groupInfo) {
2861
                $tutors = GroupManager::getTutors($groupInfo);
2862
                if (!empty($tutors)) {
2863
                    SurveyUtil::saveInviteMail(
2864
                        $survey,
2865
                        ' ',
2866
                        ' ',
2867
                        false
2868
                    );
2869
2870
                    foreach ($tutors as $tutor) {
2871
                        $subject = sprintf(get_lang('GroupSurveyX'), $groupInfo['name']);
2872
                        $content = sprintf(
2873
                            get_lang('HelloXGroupX'),
2874
                            $tutor['complete_name'],
2875
                            $groupInfo['name']
2876
                        );
2877
2878
                        SurveyUtil::saveInvitations(
2879
                            $surveyId,
2880
                            ['users' => $tutor['user_id']],
2881
                            $subject,
2882
                            $content,
2883
                            false,
2884
                            true,
2885
                            false,
2886
                            true
2887
                        );
2888
                    }
2889
                    Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false));
2890
                }
2891
                SurveyUtil::update_count_invited($survey->getCode());
2892
2893
                return true;
2894
            }
2895
        }
2896
2897
        return false;
2898
    }
2899
}
2900