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

SurveyManager::get_survey()   B

Complexity

Conditions 9
Paths 33

Size

Total Lines 57
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 38
nc 33
nop 4
dl 0
loc 57
rs 7.7564
c 1
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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

363
                Event::/** @scrutinizer ignore-call */ 
364
                       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...
364
                    LOG_SURVEY_CREATED,
365
                    LOG_SURVEY_ID,
366
                    $survey_id,
367
                    null,
368
                    api_get_user_id(),
369
                    api_get_course_int_id(),
370
                    api_get_session_id()
371
                );
372
373
                // Insert into item_property
374
                /*api_item_property_update(
375
                    api_get_course_info(),
376
                    TOOL_SURVEY,
377
                    $survey_id,
378
                    'SurveyAdded',
379
                    api_get_user_id()
380
                );*/
381
            }
382
383
            if (1 == $values['survey_type'] && !empty($values['parent_id'])) {
384
                self::copy_survey($values['parent_id'], $survey_id);
385
            }
386
387
            Display::addFlash(
388
                Display::return_message(
389
                    get_lang('The survey has been created succesfully'),
390
                    'success'
391
                )
392
            );
393
            $return['id'] = $survey_id;
394
        } else {
395
            // Check whether the code doesn't soon exists in this language
396
            $sql = 'SELECT 1 FROM '.$table_survey.'
397
			        WHERE
398
			            code = "'.Database::escape_string($values['survey_code']).'" AND
399
			            lang = "'.Database::escape_string($values['survey_language']).'" AND
400
			            iid !='.intval($values['survey_id']);
401
            $rs = Database::query($sql);
402
            if (Database::num_rows($rs) > 0) {
403
                Display::addFlash(
404
                    Display::return_message(
405
                        get_lang('This survey code soon exists in this language'),
406
                        'error'
407
                    )
408
                );
409
                $return['type'] = 'error';
410
                $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0;
411
412
                return $return;
413
            }
414
415
            if (!isset($values['anonymous'])
416
                || (isset($values['anonymous']) && '' == $values['anonymous'])
417
            ) {
418
                $values['anonymous'] = 0;
419
            }
420
421
            /** @var CSurvey $survey */
422
            $survey = $repo->find($values['survey_id']);
423
424
            $extraParams = [];
425
            $survey->setOneQuestionPerPage(isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0);
426
            $survey->setShuffle(isset($values['shuffle']) ? $values['shuffle'] : 0);
427
428
            if (0 == $values['anonymous']) {
429
                $survey->setShowFormProfile(isset($values['show_form_profile']) ? $values['show_form_profile'] : 0);
430
                $isFormProfile = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0;
431
                if (1 == $isFormProfile) {
432
                    $fields = explode(',', $values['input_name_list']);
433
                    $field_values = '';
434
                    foreach ($fields as &$field) {
435
                        if ('' != $field) {
436
                            if (!isset($values[$field]) ||
437
                                (isset($values[$field]) && '' == $values[$field])
438
                            ) {
439
                                $values[$field] = 0;
440
                            }
441
                            $field_values .= $field.':'.$values[$field].'@';
442
                        }
443
                    }
444
                    $survey->setFormFields($field_values);
445
                } else {
446
                    $survey->setFormFields('');
447
                }
448
            } else {
449
                $survey->setFormFields('');
450
                $survey->setShowFormProfile(0);
451
            }
452
453
            $survey
454
                ->setTitle($values['survey_title'])
455
                ->setSubtitle($values['survey_title'])
456
                ->setLang($values['survey_language'])
457
                ->setAvailFrom(api_get_utc_datetime($values['start_date'].':00', true, true))
458
                ->setAvailTill(api_get_utc_datetime($values['end_date'].':59', true, true))
459
                ->setIsShared($shared_survey_id)
460
                ->setTemplate('template')
461
                ->setIntro($values['survey_introduction'])
462
                ->setSurveyThanks($values['survey_thanks'])
463
                ->setAnonymous((string) $values['anonymous'])
464
                ->setVisibleResults((int) $values['visible_results'])
465
            ;
466
467
            $repo->update($survey);
468
            /*
469
            // Update into item_property (update)
470
            api_item_property_update(
471
                api_get_course_info(),
472
                TOOL_SURVEY,
473
                $values['survey_id'],
474
                'SurveyUpdated',
475
                api_get_user_id()
476
            );*/
477
478
            Display::addFlash(
479
                Display::return_message(
480
                    get_lang('The survey has been updated succesfully'),
481
                    'confirmation'
482
                )
483
            );
484
485
            $return['id'] = $values['survey_id'];
486
        }
487
488
        $survey_id = (int) $return['id'];
489
490
        // Gradebook
491
        $gradebook_option = false;
492
        if (isset($values['survey_qualify_gradebook'])) {
493
            $gradebook_option = $values['survey_qualify_gradebook'] > 0;
494
        }
495
496
        $gradebook_link_type = 8;
497
        $link_info = GradebookUtils::isResourceInCourseGradebook(
498
            $courseCode,
499
            $gradebook_link_type,
500
            $survey_id,
501
            $session_id
502
        );
503
504
        $gradebook_link_id = isset($link_info['id']) ? $link_info['id'] : false;
505
506
        if ($gradebook_option) {
507
            if ($survey_id > 0) {
508
                $title_gradebook = ''; // Not needed here.
509
                $description_gradebook = ''; // Not needed here.
510
                $survey_weight = floatval($_POST['survey_weight']);
511
                $max_score = 1;
512
513
                if (!$gradebook_link_id) {
514
                    GradebookUtils::add_resource_to_course_gradebook(
515
                        $values['category_id'],
516
                        $courseCode,
517
                        $gradebook_link_type,
518
                        $survey_id,
519
                        $title_gradebook,
520
                        $survey_weight,
521
                        $max_score,
522
                        $description_gradebook,
523
                        1,
524
                        $session_id
525
                    );
526
                } else {
527
                    GradebookUtils::updateResourceFromCourseGradebook(
528
                        $gradebook_link_id,
529
                        $courseCode,
530
                        $survey_weight
531
                    );
532
                }
533
            }
534
        } else {
535
            // Delete everything of the gradebook for this $linkId
536
            GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id);
537
        }
538
539
        return $return;
540
    }
541
542
    public static function deleteSurvey(CSurvey $survey)
543
    {
544
        $repo = Container::getSurveyRepository();
545
        $surveyId = $survey->getIid();
546
        $repo->delete($survey);
547
548
        $table_survey = Database::get_course_table(TABLE_SURVEY);
549
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
550
551
        Event::addEvent(
552
            LOG_SURVEY_DELETED,
553
            LOG_SURVEY_ID,
554
            $surveyId,
555
            null,
556
            api_get_user_id(),
557
            api_get_course_int_id(),
558
            api_get_session_id()
559
        );
560
561
        /*// Deleting groups of this survey
562
        $sql = "DELETE FROM $table_survey_question_group
563
                WHERE c_id = $course_id AND iid='".$survey_id."'";
564
        Database::query($sql);*/
565
566
        // Deleting the questions of the survey
567
        self::delete_all_survey_questions($surveyId, false);
568
569
        // Update into item_property (delete)
570
        /*api_item_property_update(
571
            $course_info,
572
            TOOL_SURVEY,
573
            $survey_id,
574
            'SurveyDeleted',
575
            api_get_user_id()
576
        );*/
577
578
        Skill::deleteSkillsFromItem($surveyId, ITEM_TYPE_SURVEY);
579
580
        return true;
581
    }
582
583
    /**
584
     * Copy given survey to a new (optional) given survey ID.
585
     *
586
     * @param int $survey_id
587
     * @param int $new_survey_id
588
     * @param int $targetCourseId
589
     *
590
     * @return bool
591
     */
592
    public static function copy_survey($survey_id, $new_survey_id = null, $targetCourseId = null)
593
    {
594
        $course_id = api_get_course_int_id();
595
        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...
596
            $targetCourseId = $course_id;
597
        }
598
599
        // Database table definitions
600
        $table_survey = Database::get_course_table(TABLE_SURVEY);
601
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
602
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
603
        $table_survey_options = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
604
        $survey_id = (int) $survey_id;
605
606
        // Get groups
607
        $survey_data = self::get_survey($survey_id, 0, null, true);
608
        if (empty($survey_data)) {
609
            return true;
610
        }
611
612
        if (empty($new_survey_id)) {
613
            $params = $survey_data;
614
            $params['code'] = self::generate_unique_code($params['code']);
615
            $params['c_id'] = $targetCourseId;
616
            unset($params['survey_id']);
617
            $params['session_id'] = api_get_session_id();
618
            $params['title'] = $params['title'].' '.get_lang('Copy');
619
            unset($params['iid']);
620
            $params['invited'] = 0;
621
            $params['answered'] = 0;
622
            $new_survey_id = Database::insert($table_survey, $params);
623
624
            if ($new_survey_id) {
625
                // Insert into item_property
626
                /*api_item_property_update(
627
                    api_get_course_info(),
628
                    TOOL_SURVEY,
629
                    $new_survey_id,
630
                    'SurveyAdded',
631
                    api_get_user_id()
632
                );*/
633
            }
634
        } else {
635
            $new_survey_id = (int) $new_survey_id;
636
        }
637
638
        $sql = "SELECT * FROM $table_survey_question_group
639
                WHERE c_id = $course_id AND iid = $survey_id";
640
        $res = Database::query($sql);
641
        while ($row = Database::fetch_array($res, 'ASSOC')) {
642
            $params = [
643
                'c_id' => $targetCourseId,
644
                'name' => $row['name'],
645
                'description' => $row['description'],
646
                'survey_id' => $new_survey_id,
647
            ];
648
            $insertId = Database::insert($table_survey_question_group, $params);
649
650
            $sql = "UPDATE $table_survey_question_group SET id = iid
651
                    WHERE iid = $insertId";
652
            Database::query($sql);
653
654
            $group_id[$row['id']] = $insertId;
655
        }
656
657
        // Get questions
658
        $sql = "SELECT * FROM $table_survey_question
659
                WHERE c_id = $course_id AND survey_id = $survey_id";
660
        $res = Database::query($sql);
661
        while ($row = Database::fetch_array($res, 'ASSOC')) {
662
            $params = [
663
                'c_id' => $targetCourseId,
664
                'survey_id' => $new_survey_id,
665
                'survey_question' => $row['survey_question'],
666
                'survey_question_comment' => $row['survey_question_comment'],
667
                'type' => $row['type'],
668
                'display' => $row['display'],
669
                'sort' => $row['sort'],
670
                'shared_question_id' => $row['shared_question_id'],
671
                'max_value' => $row['max_value'],
672
                'survey_group_pri' => $row['survey_group_pri'],
673
                'survey_group_sec1' => $row['survey_group_sec1'],
674
                'survey_group_sec2' => $row['survey_group_sec2'],
675
            ];
676
677
            if (api_get_configuration_value('allow_required_survey_questions')) {
678
                if (isset($row['is_required'])) {
679
                    $params['is_required'] = $row['is_required'];
680
                }
681
            }
682
683
            $insertId = Database::insert($table_survey_question, $params);
684
            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...
685
                /*$sql = "UPDATE $table_survey_question SET question_id = iid WHERE iid = $insertId";
686
                Database::query($sql);*/
687
                $question_id[$row['question_id']] = $insertId;
688
            }
689
        }
690
691
        // Get questions options
692
        $sql = "SELECT * FROM $table_survey_options
693
                WHERE c_id = $course_id AND survey_id='".$survey_id."'";
694
695
        $res = Database::query($sql);
696
        while ($row = Database::fetch_array($res, 'ASSOC')) {
697
            $params = [
698
                'c_id' => $targetCourseId,
699
                '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...
700
                'survey_id' => $new_survey_id,
701
                'option_text' => $row['option_text'],
702
                'sort' => $row['sort'],
703
                'value' => $row['value'],
704
            ];
705
            $insertId = Database::insert($table_survey_options, $params);
706
            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...
707
                $sql = "UPDATE $table_survey_options SET question_option_id = $insertId
708
                        WHERE iid = $insertId";
709
                Database::query($sql);
710
            }
711
        }
712
713
        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...
714
    }
715
716
    /**
717
     * This function duplicates a survey (and also all the question in that survey.
718
     *
719
     * @param int $surveyId id of the survey that has to be duplicated
720
     * @param int $courseId id of the course which survey has to be duplicated
721
     *
722
     * @return true
723
     *
724
     * @author Eric Marguin <[email protected]>, Elixir Interactive
725
     *
726
     * @version October 2007
727
     */
728
    public static function empty_survey($surveyId, $courseId = 0)
729
    {
730
        // Database table definitions
731
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
732
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
733
        $table_survey = Database::get_course_table(TABLE_SURVEY);
734
735
        $courseId = (int) $courseId;
736
        $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
737
        $surveyId = (int) $surveyId;
738
739
        $datas = self::get_survey($surveyId);
740
        $session_where = '';
741
        if (0 != api_get_session_id()) {
742
            $session_where = ' AND session_id = "'.api_get_session_id().'" ';
743
        }
744
745
        $sql = 'DELETE FROM '.$table_survey_invitation.'
746
		        WHERE
747
		            c_id = '.$courseId.' AND
748
		            survey_code = "'.Database::escape_string($datas['code']).'" '.$session_where.' ';
749
        Database::query($sql);
750
751
        $sql = 'DELETE FROM '.$table_survey_answer.'
752
		        WHERE c_id = '.$courseId.' AND survey_id='.$surveyId;
753
        Database::query($sql);
754
755
        $sql = 'UPDATE '.$table_survey.' SET invited=0, answered=0
756
		        WHERE c_id = '.$courseId.' AND iid ='.$surveyId;
757
        Database::query($sql);
758
759
        Event::addEvent(
760
            LOG_SURVEY_CLEAN_RESULTS,
761
            LOG_SURVEY_ID,
762
            $surveyId,
763
            null,
764
            api_get_user_id(),
765
            api_get_course_int_id(),
766
            api_get_session_id()
767
        );
768
769
        return true;
770
    }
771
772
    /**
773
     * Updates c_survey.answered: number of people who have taken the survey (=filled at least one question).
774
     */
775
    public static function updateSurveyAnswered(CSurvey $survey, $user)
776
    {
777
        $em = Database::getManager();
778
        $surveyId = $survey->getIid();
779
        $courseId = api_get_course_int_id();
780
        $sessionId = api_get_session_id();
781
782
        $survey->setAnswered($survey->getAnswered() + 1);
783
        $em->persist($survey);
784
        $em->flush();
785
786
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
787
        // Storing that the user has finished the survey.
788
        $sql = "UPDATE $table
789
                SET
790
                    answered_at = '".api_get_utc_datetime()."',
791
                    answered = 1
792
                WHERE
793
                    c_id = $courseId AND
794
                    session_id = $sessionId AND
795
                    user ='".Database::escape_string($user)."' AND
796
                    survey_id ='".$surveyId."'";
797
        Database::query($sql);
798
    }
799
800
    /**
801
     * This function return the "icon" of the question type.
802
     *
803
     * @param string $type
804
     *
805
     * @author Patrick Cool <[email protected]>, Ghent University
806
     *
807
     * @version February 2007
808
     */
809
    public static function icon_question($type)
810
    {
811
        // the possible question types
812
        $possible_types = [
813
            'personality',
814
            'yesno',
815
            'multiplechoice',
816
            'multipleresponse',
817
            'open',
818
            'dropdown',
819
            'comment',
820
            'pagebreak',
821
            'percentage',
822
            'score',
823
        ];
824
825
        // the images array
826
        $icon_question = [
827
            'yesno' => 'yesno.png',
828
            'personality' => 'yesno.png',
829
            'multiplechoice' => 'mcua.png',
830
            'multipleresponse' => 'mcma.png',
831
            'open' => 'open_answer.png',
832
            'dropdown' => 'dropdown.png',
833
            'percentage' => 'percentagequestion.png',
834
            'score' => 'scorequestion.png',
835
            'comment' => 'commentquestion.png',
836
            'pagebreak' => 'page_end.png',
837
        ];
838
839
        if (in_array($type, $possible_types)) {
840
            return $icon_question[$type];
841
        }
842
843
        return false;
844
    }
845
846
    /**
847
     * This function retrieves all the information of a question.
848
     *
849
     * @param int  $question_id the id of the question
850
     * @param bool $shared
851
     *
852
     * @return array
853
     *
854
     * @author Patrick Cool <[email protected]>, Ghent University
855
     *
856
     * @version January 2007
857
     *
858
     * @todo one sql call should do the trick
859
     */
860
    public static function get_question($question_id)
861
    {
862
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
863
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
864
        $course_id = api_get_course_int_id();
865
        $question_id = (int) $question_id;
866
867
        if (empty($question_id)) {
868
            return [];
869
        }
870
871
        $sql = "SELECT * FROM $tbl_survey_question
872
                WHERE iid = $question_id
873
                ORDER BY `sort` ";
874
875
        $sqlOption = "  SELECT * FROM $table_survey_question_option
876
                        WHERE question_id='".$question_id."'
877
                        ORDER BY `sort` ";
878
        // Getting the information of the question
879
        $result = Database::query($sql);
880
        $row = Database::fetch_array($result, 'ASSOC');
881
882
        $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...
883
        $return['parent_id'] = isset($row['parent_id']) ? $row['parent_id'] : 0;
884
        $return['parent_option_id'] = isset($row['parent_option_id']) ? $row['parent_option_id'] : 0;
885
        $return['question_id'] = $row['iid'];
886
        $return['type'] = $row['type'];
887
        $return['question'] = $row['survey_question'];
888
        $return['horizontalvertical'] = $row['display'];
889
        $return['shared_question_id'] = $row['shared_question_id'];
890
        $return['maximum_score'] = $row['max_value'];
891
        $return['is_required'] = api_get_configuration_value('allow_required_survey_questions')
892
            ? $row['is_required']
893
            : false;
894
895
        if (0 != $row['survey_group_pri']) {
896
            $return['assigned'] = $row['survey_group_pri'];
897
            $return['choose'] = 1;
898
        } else {
899
            $return['assigned1'] = $row['survey_group_sec1'];
900
            $return['assigned2'] = $row['survey_group_sec2'];
901
            $return['choose'] = 2;
902
        }
903
904
        // Getting the information of the question options
905
        $result = Database::query($sqlOption);
906
        $counter = 0;
907
        while ($row = Database::fetch_array($result, 'ASSOC')) {
908
            /** @todo this should be renamed to options instead of answers */
909
            $return['answers'][] = $row['option_text'];
910
            $return['values'][] = $row['value'];
911
            $return['answer_data'][$counter]['data'] = $row['option_text'];
912
            $return['answer_data'][$counter]['iid'] = $row['iid'];
913
            /** @todo this can be done more elegantly (used in reporting) */
914
            $return['answersid'][] = $row['iid'];
915
            $counter++;
916
        }
917
918
        return $return;
919
    }
920
921
    /**
922
     * This function gets all the question of any given survey.
923
     *
924
     * @param int $surveyId the id of the survey
925
     * @param int $courseId
926
     *
927
     * @return array containing all the questions of the survey
928
     *
929
     * @author Patrick Cool <[email protected]>, Ghent University
930
     * @deprecated
931
     * @version February 2007
932
     *
933
     * @todo one sql call should do the trick
934
     */
935
    public static function get_questions($surveyId, $courseId = 0)
936
    {
937
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
938
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
939
940
        $courseId = (int) $courseId;
941
        $surveyId = (int) $surveyId;
942
943
        if (empty($courseId)) {
944
            $courseId = api_get_course_int_id();
945
        }
946
947
        // Getting the information of the question
948
        $sql = "SELECT * FROM $tbl_survey_question
949
		        WHERE survey_id= $surveyId ";
950
        $result = Database::query($sql);
951
        $questions = [];
952
        while ($row = Database::fetch_array($result, 'ASSOC')) {
953
            $questionId = $row['iid'];
954
            $questions[$questionId]['survey_id'] = $surveyId;
955
            $questions[$questionId]['question_id'] = $questionId;
956
            $questions[$questionId]['type'] = $row['type'];
957
            $questions[$questionId]['question'] = $row['survey_question'];
958
            $questions[$questionId]['horizontalvertical'] = $row['display'];
959
            $questions[$questionId]['maximum_score'] = $row['max_value'];
960
            $questions[$questionId]['sort'] = $row['sort'];
961
            $questions[$questionId]['survey_question_comment'] = $row['survey_question_comment'];
962
963
            // Getting the information of the question options
964
            $sql = "SELECT * FROM $table_survey_question_option
965
		             WHERE survey_id= $surveyId  AND question_id = $questionId";
966
            $resultOptions = Database::query($sql);
967
            while ($rowOption = Database::fetch_array($resultOptions, 'ASSOC')) {
968
                $questions[$questionId]['answers'][] = $rowOption['option_text'];
969
            }
970
        }
971
972
        return $questions;
973
    }
974
975
    public static function saveQuestion(CSurvey $survey, array $form_content, bool $showMessage = true, array $dataFromDatabase = [])
976
    {
977
        $surveyId = $survey->getIid();
978
979
        $message = '';
980
        if (strlen($form_content['question']) > 1) {
981
            // Checks length of the question
982
            $empty_answer = false;
983
            if (1 == $survey->getSurveyType()) {
984
                if (empty($form_content['choose'])) {
985
                    return 'PleaseChooseACondition';
986
                }
987
988
                if ((2 == $form_content['choose']) &&
989
                    ($form_content['assigned1'] == $form_content['assigned2'])
990
                ) {
991
                    return 'ChooseDifferentCategories';
992
                }
993
            }
994
995
            if ('percentage' !== $form_content['type']) {
996
                if (isset($form_content['answers'])) {
997
                    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...
998
                        if (strlen($form_content['answers'][$i]) < 1) {
999
                            $empty_answer = true;
1000
                            break;
1001
                        }
1002
                    }
1003
                }
1004
            }
1005
1006
            if ('score' === $form_content['type']) {
1007
                if (strlen($form_content['maximum_score']) < 1) {
1008
                    $empty_answer = true;
1009
                }
1010
            }
1011
1012
            $em = Database::getManager();
1013
            $course_id = api_get_course_int_id();
1014
            if (!$empty_answer) {
1015
                // Table definitions
1016
                $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1017
1018
                // Getting all the information of the survey
1019
                $survey_data = self::get_survey($surveyId);
1020
1021
                // Storing a new question
1022
                if ('' == $form_content['question_id'] || !is_numeric($form_content['question_id'])) {
1023
                    // Finding the max sort order of the questions in the given survey
1024
                    $sql = "SELECT max(sort) AS max_sort
1025
					        FROM $tbl_survey_question
1026
                            WHERE survey_id = $surveyId ";
1027
                    $result = Database::query($sql);
1028
                    $row = Database::fetch_array($result, 'ASSOC');
1029
                    $max_sort = $row['max_sort'];
1030
1031
                    $question = new CSurveyQuestion();
1032
1033
                    // Some variables defined for survey-test type
1034
                    if (isset($_POST['choose'])) {
1035
                        if (1 == $_POST['choose']) {
1036
                            $question->setSurveyGroupPri($_POST['assigned']);
1037
                        } elseif (2 == $_POST['choose']) {
1038
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1039
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1040
                        }
1041
                    }
1042
1043
                    $question
1044
                        ->setSurveyQuestionComment($form_content['question_comment'] ?? '')
1045
                        ->setMaxValue($form_content['maximum_score'] ?? 0)
1046
                        ->setDisplay($form_content['horizontalvertical'] ?? '')
1047
                        //->setCId($course_id)
1048
                        ->setSurvey($survey)
1049
                        ->setSurveyQuestion($form_content['question'])
1050
                        ->setType($form_content['type'])
1051
                        ->setSort($max_sort + 1)
1052
                        ->setSharedQuestionId((int) $form_content['shared_question_id'])
1053
                    ;
1054
1055
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1056
                        $question->setIsMandatory(isset($form_content['is_required']));
1057
                    }
1058
1059
                    if (api_get_configuration_value('survey_question_dependency')) {
1060
                        $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...
1061
                        $params['parent_option_id'] = 0;
1062
                        if (isset($form_content['parent_id']) &&
1063
                            isset($form_content['parent_option_id']) &&
1064
                            !empty($form_content['parent_id']) &&
1065
                            !empty($form_content['parent_option_id'])
1066
                        ) {
1067
                            $params['parent_id'] = $form_content['parent_id'];
1068
                            $params['parent_option_id'] = $form_content['parent_option_id'];
1069
                        }
1070
                    }
1071
1072
                    $em->persist($question);
1073
                    $em->flush();
1074
1075
                    $question_id = $question->getIid();
1076
                    if ($question_id) {
1077
                        /*$sql = "UPDATE $tbl_survey_question SET question_id = $question_id
1078
                                WHERE iid = $question_id";
1079
                        Database::query($sql);*/
1080
                        $form_content['question_id'] = $question_id;
1081
                        $message = 'The question has been added.';
1082
                    }
1083
                } else {
1084
                    $repo = $em->getRepository(CSurveyQuestion::class);
1085
                    $repoOption = $em->getRepository(CSurveyQuestionOption::class);
1086
                    /** @var CSurveyQuestion $question */
1087
                    $question = $repo->find($form_content['question_id']);
1088
1089
                    if (isset($_POST['choose'])) {
1090
                        if (1 == $_POST['choose']) {
1091
                            $question->setSurveyGroupPri($_POST['assigned']);
1092
                            $question->setSurveyGroupSec1(0);
1093
                            $question->setSurveyGroupSec2(0);
1094
                        } elseif (2 == $_POST['choose']) {
1095
                            $question->setSurveyGroupPri(0);
1096
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1097
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1098
                        }
1099
                    }
1100
1101
                    $maxScore = isset($form_content['maximum_score']) ? $form_content['maximum_score'] : null;
1102
                    $questionComment = $form_content['question_comment'] ?? '';
1103
                    $question
1104
                        ->setSurveyQuestionComment($questionComment)
1105
                        ->setSurveyQuestion($form_content['question'])
1106
                        ->setDisplay($form_content['horizontalvertical'])
1107
                    ;
1108
1109
                    if (api_get_configuration_value('allow_required_survey_questions')) {
1110
                        $question->isMandatory(isset($form_content['is_required']));
1111
                    }
1112
1113
                    if (api_get_configuration_value('survey_question_dependency')) {
1114
                        $params['parent_id'] = 0;
1115
                        $params['parent_option_id'] = 0;
1116
                        if (isset($form_content['parent_id']) &&
1117
                            isset($form_content['parent_option_id']) &&
1118
                            !empty($form_content['parent_id']) &&
1119
                            !empty($form_content['parent_option_id'])
1120
                        ) {
1121
                            $question->setParent($repo->find($form_content['parent_id']));
1122
                            $question->setParentOption($repoOption->find($form_content['parent_option_id']));
1123
                        }
1124
                    }
1125
1126
                    $em->persist($question);
1127
                    $em->flush();
1128
                    $message = 'QuestionUpdated';
1129
                }
1130
                // Storing the options of the question
1131
                self::saveQuestionOptions($survey, $question, $form_content, $dataFromDatabase);
1132
            } else {
1133
                $message = 'PleasFillAllAnswer';
1134
            }
1135
        } else {
1136
            $message = 'PleaseEnterAQuestion';
1137
        }
1138
1139
        if ($showMessage) {
1140
            if (!empty($message)) {
1141
                Display::addFlash(Display::return_message(get_lang($message)));
1142
            }
1143
        }
1144
1145
        return $message;
1146
    }
1147
1148
    /**
1149
     * This functions moves a question of a survey up or down.
1150
     *
1151
     * @param string $direction
1152
     * @param int    $survey_question_id
1153
     * @param int    $survey_id
1154
     *
1155
     * @author Patrick Cool <[email protected]>, Ghent University
1156
     *
1157
     * @version January 2007
1158
     */
1159
    public static function move_survey_question($direction, $survey_question_id, $survey_id)
1160
    {
1161
        // Table definition
1162
        $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1163
        $course_id = api_get_course_int_id();
1164
1165
        if ('moveup' === $direction) {
1166
            $sort = 'DESC';
1167
        }
1168
        if ('movedown' === $direction) {
1169
            $sort = 'ASC';
1170
        }
1171
1172
        $survey_id = (int) $survey_id;
1173
1174
        // Finding the two questions that needs to be swapped
1175
        $sql = "SELECT * FROM $table_survey_question
1176
		        WHERE c_id = $course_id AND survey_id='".$survey_id."'
1177
		        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...
1178
        $result = Database::query($sql);
1179
        $found = false;
1180
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1181
            if ($found) {
1182
                $question_id_two = $row['question_id'];
1183
                $question_sort_two = $row['sort'];
1184
                $found = false;
1185
            }
1186
            if ($row['question_id'] == $survey_question_id) {
1187
                $found = true;
1188
                $question_id_one = $row['question_id'];
1189
                $question_sort_one = $row['sort'];
1190
            }
1191
        }
1192
1193
        $sql = "UPDATE $table_survey_question
1194
                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...
1195
		        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...
1196
        Database::query($sql);
1197
1198
        $sql = "UPDATE $table_survey_question
1199
                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...
1200
		        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...
1201
        Database::query($sql);
1202
    }
1203
1204
    /**
1205
     * This function deletes all the questions of a given survey
1206
     * This function is normally only called when a survey is deleted.
1207
     *
1208
     * @param int $survey_id the id of the survey that has to be deleted
1209
     *
1210
     * @return bool
1211
     *
1212
     * @author Patrick Cool <[email protected]>, Ghent University
1213
     *
1214
     * @version January 2007
1215
     */
1216
    public static function delete_all_survey_questions($survey_id, $shared = false)
1217
    {
1218
        $course_id = api_get_course_int_id();
1219
        $survey_id = (int) $survey_id;
1220
1221
        /*$sql = "DELETE FROM $table_survey_question
1222
		        WHERE $course_condition survey_id = '".$survey_id."'";
1223
1224
        // Deleting the survey questions
1225
        Database::query($sql);*/
1226
1227
        // Deleting all the options of the questions of the survey
1228
        //self::delete_all_survey_questions_options($survey_id, $shared);
1229
1230
        // Deleting all the answers on this survey
1231
        //self::delete_all_survey_answers($survey_id);
1232
1233
        return true;
1234
    }
1235
1236
    public static function deleteQuestion($questionId)
1237
    {
1238
        $questionId = (int) $questionId;
1239
        if (empty($questionId)) {
1240
            return false;
1241
        }
1242
1243
        $em = Database::getManager();
1244
        $repo = Container::getSurveyQuestionRepository();
1245
        $question = $repo->find($questionId);
1246
        if ($question) {
1247
            $em->remove($question);
1248
            $em->flush();
1249
1250
            return true;
1251
        }
1252
1253
        return false;
1254
    }
1255
1256
    public static function saveQuestionOptions(CSurvey $survey, CSurveyQuestion $question, $form_content, $dataFromDatabase = [])
1257
    {
1258
        $course_id = api_get_course_int_id();
1259
        $type = $form_content['type'];
1260
1261
        // A percentage question type has options 1 -> 100
1262
        if ('percentage' === $type) {
1263
            for ($i = 1; $i < 101; $i++) {
1264
                $form_content['answers'][] = $i;
1265
            }
1266
        }
1267
        $em = Database::getManager();
1268
1269
        // Table definition
1270
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1271
1272
        // We are editing a question so we first have to remove all the existing options from the database
1273
        $optionsToDelete = [];
1274
        if (isset($dataFromDatabase['answer_data'])) {
1275
            foreach ($dataFromDatabase['answer_data'] as $data) {
1276
                if ('other' === $data['data'] && 'multiplechoiceother' === $type) {
1277
                    continue;
1278
                }
1279
1280
                if (!in_array($data['iid'], $form_content['answersid'])) {
1281
                    $optionsToDelete[] = $data['iid'];
1282
                }
1283
            }
1284
        }
1285
1286
        if (!empty($optionsToDelete)) {
1287
            foreach ($optionsToDelete as $iid) {
1288
                $iid = (int) $iid;
1289
                $sql = "DELETE FROM $table
1290
			            WHERE
1291
			                iid = $iid AND
1292
			                c_id = $course_id AND
1293
                            question_id = '".intval($form_content['question_id'])."'
1294
                            ";
1295
                Database::query($sql);
1296
            }
1297
        }
1298
1299
        $counter = 1;
1300
        if (isset($form_content['answers']) && is_array($form_content['answers'])) {
1301
            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...
1302
                $values = isset($form_content['values']) ? (int) $form_content['values'][$i] : 0;
1303
                $answerId = 0;
1304
                if (isset($form_content['answersid']) && isset($form_content['answersid'][$i])) {
1305
                    $answerId = $form_content['answersid'][$i];
1306
                }
1307
                if (empty($answerId)) {
1308
                    $option = new CSurveyQuestionOption();
1309
                    $option
1310
                        ->setQuestion($question)
1311
                        ->setOptionText($form_content['answers'][$i])
1312
                        ->setSurvey($survey)
1313
                        ->setValue($values)
1314
                        ->setSort($counter)
1315
                    ;
1316
                    $em->persist($option);
1317
                    $em->flush();
1318
                    $insertId = $option->getIid();
1319
                    if ($insertId) {
1320
                        $counter++;
1321
                    }
1322
                } else {
1323
                    $repo = $em->getRepository(CSurveyQuestionOption::class);
1324
                    /** @var CSurveyQuestionOption $option */
1325
                    $option = $repo->find($answerId);
1326
                    if ($option) {
1327
                        $option
1328
                            ->setOptionText($form_content['answers'][$i])
1329
                            ->setValue($values)
1330
                            ->setSort($counter)
1331
                        ;
1332
                        $em->persist($option);
1333
                        $em->flush();
1334
                    }
1335
                    $counter++;
1336
                }
1337
            }
1338
        }
1339
1340
        if ('multiplechoiceother' === $type) {
1341
            if (empty($dataFromDatabase['answer_data'])) {
1342
                $params = [
1343
                    'question_id' => $form_content['question_id'],
1344
                    'survey_id' => $form_content['survey_id'],
1345
                    'option_text' => 'other',
1346
                    'value' => 0,
1347
                    'sort' => $counter,
1348
                ];
1349
                Database::insert($table, $params);
1350
            } else {
1351
                $params = [
1352
                    'option_text' => 'other',
1353
                    'value' => 0,
1354
                    'sort' => $counter,
1355
                ];
1356
                Database::update(
1357
                    $table,
1358
                    $params,
1359
                    [
1360
                        'question_id = ? AND survey_id = ? AND option_text = ?' => [
1361
                            $form_content['question_id'],
1362
                            $form_content['survey_id'],
1363
                            'other',
1364
                        ],
1365
                    ]
1366
                );
1367
            }
1368
        }
1369
    }
1370
1371
    /**
1372
     * This function deletes all the options of the questions of a given survey
1373
     * This function is normally only called when a survey is deleted.
1374
     *
1375
     * @param int $survey_id the id of the survey that has to be deleted
1376
     *
1377
     * @return true
1378
     *
1379
     * @author Patrick Cool <[email protected]>, Ghent University
1380
     *
1381
     * @version January 2007
1382
     */
1383
    public static function delete_all_survey_questions_options($survey_id, $shared = false)
1384
    {
1385
        // Table definitions
1386
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1387
        $course_id = api_get_course_int_id();
1388
        $course_condition = " c_id = $course_id AND ";
1389
        $sql = "DELETE FROM $table_survey_question_option
1390
                WHERE $course_condition survey_id='".intval($survey_id)."'";
1391
1392
        // Deleting the options of the survey questions
1393
        Database::query($sql);
1394
1395
        return true;
1396
    }
1397
1398
    /**
1399
     * SURVEY ANSWERS FUNCTIONS.
1400
     */
1401
1402
    /**
1403
     * This function deletes all the answers anyone has given on this survey
1404
     * This function is normally only called when a survey is deleted.
1405
     *
1406
     * @param $survey_id the id of the survey that has to be deleted
1407
     *
1408
     * @return true
1409
     *
1410
     * @todo write the function
1411
     *
1412
     * @author Patrick Cool <[email protected]>, Ghent University
1413
     *
1414
     * @version January 2007,december 2008
1415
     */
1416
    public static function delete_all_survey_answers($survey_id)
1417
    {
1418
        $course_id = api_get_course_int_id();
1419
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1420
        $survey_id = (int) $survey_id;
1421
        $sql = "DELETE FROM $table
1422
                WHERE c_id = $course_id AND survey_id = $survey_id";
1423
        Database::query($sql);
1424
1425
        return true;
1426
    }
1427
1428
    /**
1429
     * This function gets all the persons who have filled the survey.
1430
     *
1431
     * @param int $survey_id
1432
     *
1433
     * @return array
1434
     *
1435
     * @author Patrick Cool <[email protected]>, Ghent University
1436
     *
1437
     * @version February 2007
1438
     */
1439
    public static function get_people_who_filled_survey(
1440
        $survey_id,
1441
        $all_user_info = false,
1442
        $course_id = null
1443
    ) {
1444
        // Database table definition
1445
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1446
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1447
1448
        // Variable initialisation
1449
        $return = [];
1450
1451
        if (empty($course_id)) {
1452
            $course_id = api_get_course_int_id();
1453
        } else {
1454
            $course_id = (int) $course_id;
1455
        }
1456
1457
        $survey_id = (int) $survey_id;
1458
1459
        if ($all_user_info) {
1460
            $order_clause = api_sort_by_first_name()
1461
                ? ' ORDER BY user.firstname, user.lastname'
1462
                : ' ORDER BY user.lastname, user.firstname';
1463
            $sql = "SELECT DISTINCT
1464
			            answered_user.user as invited_user,
1465
			            user.firstname,
1466
			            user.lastname,
1467
			            user.id as user_id
1468
                    FROM $table_survey_answer answered_user
1469
                    LEFT JOIN $table_user as user
1470
                    ON answered_user.user = user.id
1471
                    WHERE
1472
                        survey_id= '".$survey_id."' ".
1473
                $order_clause;
1474
        } else {
1475
            $sql = "SELECT DISTINCT user FROM $table_survey_answer
1476
			        WHERE survey_id= '".$survey_id."'  ";
1477
1478
            if (api_get_configuration_value('survey_anonymous_show_answered')) {
1479
                $tblInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
1480
                $tblSurvey = Database::get_course_table(TABLE_SURVEY);
1481
1482
                $sql = "SELECT i.user FROM $tblInvitation i
1483
                    INNER JOIN $tblSurvey s
1484
                    ON i.survey_code = s.code
1485
                    WHERE i.answered IS TRUE AND s.iid = $survey_id";
1486
            }
1487
        }
1488
1489
        $res = Database::query($sql);
1490
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1491
            if ($all_user_info) {
1492
                $userInfo = api_get_user_info($row['user_id']);
1493
                $row['user_info'] = $userInfo;
1494
                $return[] = $row;
1495
            } else {
1496
                $return[] = $row['user'];
1497
            }
1498
        }
1499
1500
        return $return;
1501
    }
1502
1503
    /**
1504
     * @return bool
1505
     */
1506
    public static function survey_generation_hash_available()
1507
    {
1508
        if (extension_loaded('mcrypt')) {
1509
            return true;
1510
        }
1511
1512
        return false;
1513
    }
1514
1515
    /**
1516
     * @param int $survey_id
1517
     * @param int $course_id
1518
     * @param int $session_id
1519
     * @param int $group_id
1520
     *
1521
     * @return string
1522
     */
1523
    public static function generate_survey_hash($survey_id, $course_id, $session_id, $group_id)
1524
    {
1525
        return hash(
1526
            'sha512',
1527
            api_get_configuration_value('security_key').'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id
1528
        );
1529
    }
1530
1531
    /**
1532
     * @param int    $survey_id
1533
     * @param int    $course_id
1534
     * @param int    $session_id
1535
     * @param int    $group_id
1536
     * @param string $hash
1537
     *
1538
     * @return bool
1539
     */
1540
    public static function validate_survey_hash($survey_id, $course_id, $session_id, $group_id, $hash)
1541
    {
1542
        $generatedHash = self::generate_survey_hash($survey_id, $course_id, $session_id, $group_id);
1543
        if ($generatedHash == $hash) {
1544
            return true;
1545
        }
1546
1547
        return false;
1548
    }
1549
1550
    /**
1551
     * @param int $survey_id
1552
     * @param int $course_id
1553
     * @param int $session_id
1554
     * @param int $group_id
1555
     *
1556
     * @return string
1557
     */
1558
    public static function generate_survey_link(
1559
        $survey_id,
1560
        $course_id,
1561
        $session_id,
1562
        $group_id
1563
    ) {
1564
        $code = self::generate_survey_hash(
1565
            $survey_id,
1566
            $course_id,
1567
            $session_id,
1568
            $group_id
1569
        );
1570
1571
        return api_get_path(WEB_CODE_PATH).'survey/link.php?h='.$code.'&i='.$survey_id.'&c='.intval($course_id).'&s='
1572
            .intval($session_id).'&g='.$group_id;
1573
    }
1574
1575
    /**
1576
     * Check if the current user has mandatory surveys no-answered
1577
     * and redirect to fill the first found survey.
1578
     */
1579
    public static function protectByMandatory()
1580
    {
1581
        if (false !== strpos($_SERVER['SCRIPT_NAME'], 'fillsurvey.php')) {
1582
            return;
1583
        }
1584
1585
        $userId = api_get_user_id();
1586
        $courseId = api_get_course_int_id();
1587
        $sessionId = api_get_session_id();
1588
1589
        if (!$userId) {
1590
            return;
1591
        }
1592
1593
        if (!$courseId) {
1594
            return;
1595
        }
1596
1597
        try {
1598
            /** @var CSurveyInvitation $invitation */
1599
            $invitation = Database::getManager()
1600
                ->createQuery("
1601
                    SELECT i FROM ChamiloCourseBundle:CSurveyInvitation i
1602
                    INNER JOIN ChamiloCourseBundle:CSurvey s
1603
                        WITH (s.code = i.surveyCode AND s.cId = i.cId AND s.sessionId = i.sessionId)
1604
                    INNER JOIN ChamiloCoreBundle:ExtraFieldValues efv WITH efv.itemId = s.iid
1605
                    INNER JOIN ChamiloCoreBundle:ExtraField ef WITH efv.field = ef.id
1606
                    WHERE
1607
                        i.answered = 0 AND
1608
                        i.cId = :course AND
1609
                        i.user = :user AND
1610
                        i.sessionId = :session AND
1611
                        :now BETWEEN s.availFrom AND s.availTill AND
1612
                        ef.variable = :variable AND
1613
                        efv.value = 1 AND
1614
                        s.surveyType != 3
1615
                    ORDER BY s.availTill ASC
1616
                ")
1617
                ->setMaxResults(1)
1618
                ->setParameters([
1619
                    'course' => $courseId,
1620
                    'user' => $userId,
1621
                    'session' => $sessionId,
1622
                    'now' => new DateTime('UTC', new DateTimeZone('UTC')),
1623
                    'variable' => 'is_mandatory',
1624
                ])
1625
                ->getSingleResult();
1626
        } catch (Exception $e) {
1627
            $invitation = null;
1628
        }
1629
1630
        if (!$invitation) {
1631
            return;
1632
        }
1633
1634
        Display::addFlash(
1635
            Display::return_message(
1636
                get_lang(
1637
                    'A mandatory survey is waiting your answer. To enter the course, you must first complete the survey.'
1638
                ),
1639
                'warning'
1640
            )
1641
        );
1642
1643
        $url = SurveyUtil::generateFillSurveyLink(
1644
            $invitation->getInvitationCode(),
1645
            api_get_course_info(),
1646
            api_get_session_id()
1647
        );
1648
1649
        header('Location: '.$url);
1650
        exit;
1651
    }
1652
1653
    /**
1654
     * This function empty surveys (invitations and answers).
1655
     *
1656
     * @param int $surveyId id of the survey to empty
1657
     *
1658
     * @return bool
1659
     */
1660
    public static function emptySurveyFromId($surveyId)
1661
    {
1662
        // Database table definitions
1663
        $surveyInvitationTable = Database:: get_course_table(TABLE_SURVEY_INVITATION);
1664
        $surveyAnswerTable = Database:: get_course_table(TABLE_SURVEY_ANSWER);
1665
        $surveyTable = Database:: get_course_table(TABLE_SURVEY);
1666
        $surveyId = (int) $surveyId;
1667
        $surveyData = self::get_survey($surveyId);
1668
        if (empty($surveyData)) {
1669
            return false;
1670
        }
1671
1672
        $surveyCode = $surveyData['survey_code'];
1673
        $courseId = (int) $surveyData['c_id'];
1674
        $sessionId = (int) $surveyData['session_id'];
1675
1676
        $sql = "DELETE FROM $surveyInvitationTable
1677
                WHERE session_id = $sessionId AND c_id = $courseId AND survey_code = '$surveyCode' ";
1678
        Database::query($sql);
1679
1680
        $sql = "DELETE FROM $surveyAnswerTable
1681
                WHERE survey_id = $surveyId AND c_id = $courseId ";
1682
        Database::query($sql);
1683
1684
        $sql = "UPDATE $surveyTable
1685
                SET invited = 0, answered = 0
1686
                WHERE iid = $surveyId AND c_id = $courseId AND session_id = $sessionId ";
1687
        Database::query($sql);
1688
1689
        return true;
1690
    }
1691
1692
    /**
1693
     * Copy survey specifying course ID and session ID where will be copied.
1694
     *
1695
     * @param int $surveyId
1696
     * @param int $targetCourseId  target course id
1697
     * @param int $targetSessionId target session id
1698
     *
1699
     * @return bool|int when fails or return the new survey id
1700
     */
1701
    public static function copySurveySession($surveyId, $targetCourseId, $targetSessionId)
1702
    {
1703
        // Database table definitions
1704
        $surveyTable = Database::get_course_table(TABLE_SURVEY);
1705
        $surveyQuestionGroupTable = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
1706
        $surveyQuestionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
1707
        $surveyOptionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1708
        $surveyId = (int) $surveyId;
1709
        $targetCourseId = (int) $targetCourseId;
1710
        $targetSessionId = (int) $targetSessionId;
1711
1712
        $surveyData = self::get_survey($surveyId, 0, '', true);
1713
        if (empty($surveyData) || empty($targetCourseId)) {
1714
            return false;
1715
        }
1716
1717
        $originalCourseId = $surveyData['c_id'];
1718
        $originalSessionId = $surveyData['session_id'];
1719
1720
        $surveyData['code'] = self::generate_unique_code($surveyData['code']);
1721
        $surveyData['c_id'] = $targetCourseId;
1722
        $surveyData['session_id'] = $targetSessionId;
1723
        // Add a "Copy" suffix if copied inside the same course
1724
        if ($targetCourseId == $originalCourseId) {
1725
            $surveyData['title'] = $surveyData['title'].' '.get_lang('Copy');
1726
        }
1727
        unset($surveyData['iid']);
1728
        unset($surveyData['id']);
1729
1730
        $newSurveyId = Database::insert($surveyTable, $surveyData);
1731
1732
        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...
1733
            $sql = "SELECT * FROM $surveyQuestionGroupTable
1734
                    WHERE c_id = $originalCourseId AND survey_id = $surveyId";
1735
            $res = Database::query($sql);
1736
            while ($row = Database::fetch_array($res, 'ASSOC')) {
1737
                $params = [
1738
                    'c_id' => $targetCourseId,
1739
                    'name' => $row['name'],
1740
                    'description' => $row['description'],
1741
                    'survey_id' => $newSurveyId,
1742
                ];
1743
                $insertId = Database::insert($surveyQuestionGroupTable, $params);
1744
                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...
1745
                    $sql = "UPDATE $surveyQuestionGroupTable SET id = iid WHERE iid = $insertId";
1746
                    Database::query($sql);
1747
                    $group_id[$row['id']] = $insertId;
1748
                }
1749
            }
1750
1751
            // Get questions
1752
            $sql = "SELECT * FROM $surveyQuestionTable
1753
                    WHERE c_id = $originalCourseId AND survey_id = $surveyId";
1754
            $res = Database::query($sql);
1755
            while ($row = Database::fetch_array($res, 'ASSOC')) {
1756
                $params = [
1757
                    'c_id' => $targetCourseId,
1758
                    'survey_id' => $newSurveyId,
1759
                    'survey_question' => $row['survey_question'],
1760
                    'survey_question_comment' => $row['survey_question_comment'],
1761
                    'type' => $row['type'],
1762
                    'display' => $row['display'],
1763
                    'sort' => $row['sort'],
1764
                    'shared_question_id' => $row['shared_question_id'],
1765
                    'max_value' => $row['max_value'],
1766
                    'survey_group_pri' => $row['survey_group_pri'],
1767
                    'survey_group_sec1' => $row['survey_group_sec1'],
1768
                    'survey_group_sec2' => $row['survey_group_sec2'],
1769
                ];
1770
1771
                if (api_get_configuration_value('allow_required_survey_questions')) {
1772
                    if (isset($row['is_required'])) {
1773
                        $params['is_required'] = $row['is_required'];
1774
                    }
1775
                }
1776
1777
                $insertId = Database::insert($surveyQuestionTable, $params);
1778
                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...
1779
                    /*$sql = "UPDATE $surveyQuestionTable
1780
                            SET question_id = iid
1781
                            WHERE iid = $insertId";
1782
                    Database::query($sql);*/
1783
1784
                    $question_id[$row['question_id']] = $insertId;
1785
                }
1786
            }
1787
1788
            // Get questions options
1789
            $sql = "SELECT * FROM $surveyOptionsTable
1790
                    WHERE survey_id = $surveyId AND c_id = $originalCourseId";
1791
1792
            $res = Database::query($sql);
1793
            while ($row = Database::fetch_array($res, 'ASSOC')) {
1794
                $params = [
1795
                    'c_id' => $targetCourseId,
1796
                    '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...
1797
                    'survey_id' => $newSurveyId,
1798
                    'option_text' => $row['option_text'],
1799
                    'sort' => $row['sort'],
1800
                    'value' => $row['value'],
1801
                ];
1802
                $insertId = Database::insert($surveyOptionsTable, $params);
1803
                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...
1804
                    $sql = "UPDATE $surveyOptionsTable SET question_option_id = $insertId WHERE iid = $insertId";
1805
                    Database::query($sql);
1806
                }
1807
            }
1808
1809
            return $newSurveyId;
1810
        }
1811
1812
        return false;
1813
    }
1814
1815
    /**
1816
     * Copy/duplicate one question (into the same survey).
1817
     * Note: Relies on the question iid to find all necessary info.
1818
     *
1819
     * @param int $questionId
1820
     *
1821
     * @return int The new question's iid, or 0 on error
1822
     */
1823
    public static function copyQuestion($questionId)
1824
    {
1825
        if (empty($questionId)) {
1826
            return 0;
1827
        }
1828
        $questionId = (int) $questionId;
1829
        $questionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
1830
        $optionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1831
1832
        // Get questions
1833
        $sql = "SELECT * FROM $questionTable WHERE iid = $questionId";
1834
        $res = Database::query($sql);
1835
        if (false == $res) {
1836
            // Could not find this question
1837
            return 0;
1838
        }
1839
        $row = Database::fetch_array($res, 'ASSOC');
1840
        $params = [
1841
            'c_id' => $row['c_id'],
1842
            'survey_id' => $row['survey_id'],
1843
            'survey_question' => trim($row['survey_question']),
1844
            'survey_question_comment' => $row['survey_question_comment'],
1845
            'type' => $row['type'],
1846
            'display' => $row['display'],
1847
            'shared_question_id' => $row['shared_question_id'],
1848
            'max_value' => $row['max_value'],
1849
            'survey_group_pri' => $row['survey_group_pri'],
1850
            'survey_group_sec1' => $row['survey_group_sec1'],
1851
            'survey_group_sec2' => $row['survey_group_sec2'],
1852
        ];
1853
        if (api_get_configuration_value('allow_required_survey_questions')) {
1854
            if (isset($row['is_required'])) {
1855
                $params['is_required'] = $row['is_required'];
1856
            }
1857
        }
1858
        // Get question position
1859
        $sqlSort = "SELECT max(sort) as sort FROM $questionTable
1860
                    WHERE survey_id = ".$row['survey_id'];
1861
        $resSort = Database::query($sqlSort);
1862
        $rowSort = Database::fetch_assoc($resSort);
1863
        $params['sort'] = $rowSort['sort'] + 1;
1864
        // Insert the new question
1865
        $insertId = Database::insert($questionTable, $params);
1866
        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...
1867
            return 0;
1868
        }
1869
1870
        // Get questions options
1871
        $sql = "SELECT * FROM $optionsTable WHERE question_id = $questionId";
1872
        $res = Database::query($sql);
1873
        while ($row = Database::fetch_assoc($res)) {
1874
            $params = [
1875
                'c_id' => $row['c_id'],
1876
                'question_id' => $insertId,
1877
                'survey_id' => $row['survey_id'],
1878
                'option_text' => $row['option_text'],
1879
                'sort' => $row['sort'],
1880
                'value' => $row['value'],
1881
            ];
1882
            Database::insert($optionsTable, $params);
1883
        }
1884
1885
        return $insertId;
1886
    }
1887
1888
    /**
1889
     * @param array $surveyData
1890
     *
1891
     * @return bool
1892
     */
1893
    public static function removeMultiplicateQuestions(CSurvey $survey, $courseId)
1894
    {
1895
        $surveyId = $survey->getIid();
1896
        $courseId = (int) $courseId;
1897
1898
        if (empty($surveyId) || empty($courseId)) {
1899
            return false;
1900
        }
1901
1902
        $questions = $survey->getQuestions();
1903
        foreach ($questions as $question) {
1904
            // Questions marked with "geneated" were created using the "multiplicate" feature.
1905
            if ('generated' === $question->getSurveyQuestionComment()) {
1906
                self::deleteQuestion($question->getIid());
1907
            }
1908
        }
1909
    }
1910
1911
    /**
1912
     * @return bool
1913
     */
1914
    public static function multiplicateQuestions(CSurvey $survey, $courseId)
1915
    {
1916
        $surveyId = $survey->getIid();
1917
1918
        if (empty($surveyId)) {
1919
            return false;
1920
        }
1921
1922
        $questions = self::get_questions($surveyId);
0 ignored issues
show
Deprecated Code introduced by
The function SurveyManager::get_questions() has been deprecated. ( Ignorable by Annotation )

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

1922
        $questions = /** @scrutinizer ignore-deprecated */ self::get_questions($surveyId);
Loading history...
1923
1924
        if (empty($questions)) {
1925
            return false;
1926
        }
1927
1928
        $extraFieldValue = new ExtraFieldValue('survey');
1929
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
1930
        $groupId = null;
1931
        if ($groupData && !empty($groupData['value'])) {
1932
            $groupId = (int) $groupData['value'];
1933
        }
1934
1935
        if (null === $groupId) {
1936
            $obj = new UserGroup();
1937
            $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...
1938
            $classList = $obj->getUserGroupInCourse($options);
1939
1940
            $classToParse = [];
1941
            foreach ($classList as $class) {
1942
                $users = $obj->get_users_by_usergroup($class['id']);
1943
                if (empty($users)) {
1944
                    continue;
1945
                }
1946
                $classToParse[] = [
1947
                    'name' => $class['name'],
1948
                    'users' => $users,
1949
                ];
1950
            }
1951
            self::parseMultiplicateUserList($classToParse, $questions, $courseId, $survey, true);
1952
        } else {
1953
            $groupInfo = GroupManager::get_group_properties($groupId);
1954
            if (!empty($groupInfo)) {
1955
                $users = GroupManager::getStudents($groupInfo['iid'], true);
1956
                if (!empty($users)) {
1957
                    $users = array_column($users, 'id');
1958
                    self::parseMultiplicateUserList(
1959
                        [
1960
                            [
1961
                                'name' => $groupInfo['name'],
1962
                                'users' => $users,
1963
                            ],
1964
                        ],
1965
                        $questions,
1966
                        $courseId,
1967
                        $survey,
1968
                        false
1969
                    );
1970
                }
1971
            }
1972
        }
1973
1974
        return true;
1975
    }
1976
1977
    public static function parseMultiplicateUserList($itemList, $questions, $courseId, CSurvey $survey, $addClassNewPage = false)
1978
    {
1979
        if (empty($itemList) || empty($questions)) {
1980
            return false;
1981
        }
1982
1983
        $surveyId = $survey->getIid();
1984
        $classTag = '{{class_name}}';
1985
        $studentTag = '{{student_full_name}}';
1986
        $classCounter = 0;
1987
1988
        $newQuestionList = [];
1989
        foreach ($questions as $question) {
1990
            $newQuestionList[$question['sort']] = $question;
1991
        }
1992
        ksort($newQuestionList);
1993
1994
        $order = api_get_configuration_value('survey_duplicate_order_by_name');
1995
        foreach ($itemList as $class) {
1996
            $className = $class['name'];
1997
            $users = $class['users'];
1998
            $userInfoList = [];
1999
            foreach ($users as $userId) {
2000
                $userInfoList[] = api_get_user_info($userId);
2001
            }
2002
2003
            if ($order) {
2004
                usort(
2005
                    $userInfoList,
2006
                    function ($a, $b) {
2007
                        return $a['lastname'] > $b['lastname'];
2008
                    }
2009
                );
2010
            }
2011
2012
            foreach ($newQuestionList as $question) {
2013
                $text = $question['question'];
2014
                if (false !== strpos($text, $classTag)) {
2015
                    $replacedText = str_replace($classTag, $className, $text);
2016
                    $values = [
2017
                        'c_id' => $courseId,
2018
                        'question_comment' => 'generated',
2019
                        'type' => $question['type'],
2020
                        'display' => $question['horizontalvertical'],
2021
                        'horizontalvertical' => $question['horizontalvertical'],
2022
                        'question' => $replacedText,
2023
                        'survey_id' => $surveyId,
2024
                        'question_id' => 0,
2025
                        'shared_question_id' => 0,
2026
                        'answers' => $question['answers'] ?? null,
2027
                    ];
2028
                    self::saveQuestion($survey, $values, false);
2029
                    $classCounter++;
2030
                    continue;
2031
                }
2032
2033
                foreach ($userInfoList as $userInfo) {
2034
                    if (false !== strpos($text, $studentTag)) {
2035
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
2036
                        $values = [
2037
                            'c_id' => $courseId,
2038
                            'question_comment' => 'generated',
2039
                            'type' => $question['type'],
2040
                            'display' => $question['horizontalvertical'],
2041
                            'maximum_score' => $question['maximum_score'],
2042
                            'question' => $replacedText,
2043
                            'survey_id' => $surveyId,
2044
                            'question_id' => 0,
2045
                            'shared_question_id' => 0,
2046
                        ];
2047
2048
                        $answers = [];
2049
                        if (!empty($question['answers'])) {
2050
                            foreach ($question['answers'] as $answer) {
2051
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
2052
                                $answers[] = $replacedText;
2053
                            }
2054
                        }
2055
                        $values['answers'] = $answers;
2056
                        self::saveQuestion($survey, $values, false);
2057
                    }
2058
                }
2059
2060
                if ($addClassNewPage && $classCounter < count($itemList)) {
2061
                    // Add end page
2062
                    $values = [
2063
                        'c_id' => $courseId,
2064
                        'question_comment' => 'generated',
2065
                        'type' => 'pagebreak',
2066
                        'display' => 'horizontal',
2067
                        'question' => get_lang('Question for next class'),
2068
                        'survey_id' => $surveyId,
2069
                        'question_id' => 0,
2070
                        'shared_question_id' => 0,
2071
                    ];
2072
                    self::saveQuestion($survey, $values, false);
2073
                }
2074
            }
2075
        }
2076
2077
        return true;
2078
    }
2079
2080
    public static function hasDependency(CSurvey $survey)
2081
    {
2082
        if (false === api_get_configuration_value('survey_question_dependency')) {
2083
            return false;
2084
        }
2085
2086
        $surveyId = $survey->getIid();
2087
2088
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
2089
        $sql = "SELECT COUNT(iid) count FROM $table
2090
                WHERE
2091
                    survey_id = $surveyId AND
2092
                    parent_option_id <> 0
2093
                LIMIT 1
2094
                ";
2095
        $result = Database::query($sql);
2096
        $row = Database::fetch_array($result);
2097
2098
        if ($row) {
2099
            return $row['count'] > 0;
2100
        }
2101
2102
        return false;
2103
    }
2104
2105
    /**
2106
     * @return int
2107
     */
2108
    public static function getCountPages(CSurvey $survey)
2109
    {
2110
        $surveyId = $survey->getIid();
2111
2112
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
2113
2114
        // pagebreak
2115
        $sql = "SELECT COUNT(iid) FROM $table
2116
                WHERE
2117
                    survey_question NOT LIKE '%{{%' AND
2118
                    type = 'pagebreak' AND
2119
                    survey_id = $surveyId";
2120
        $result = Database::query($sql);
2121
        $numberPageBreaks = Database::result($result, 0, 0);
2122
2123
        // No pagebreak
2124
        $sql = "SELECT COUNT(iid) FROM $table
2125
                WHERE
2126
                    survey_question NOT LIKE '%{{%' AND
2127
                    type != 'pagebreak' AND
2128
                    survey_id = $surveyId";
2129
        $result = Database::query($sql);
2130
        $countOfQuestions = Database::result($result, 0, 0);
2131
2132
        if (1 == $survey->getOneQuestionPerPage()) {
2133
            if (!empty($countOfQuestions)) {
2134
                return $countOfQuestions;
2135
            }
2136
2137
            return 1;
2138
        }
2139
2140
        if (empty($numberPageBreaks)) {
2141
            return 1;
2142
        }
2143
2144
        return $numberPageBreaks + 1;
2145
    }
2146
2147
    /**
2148
     * Check whether this survey has ended. If so, display message and exit this script.
2149
     */
2150
    public static function checkTimeAvailability(?CSurvey $survey)
2151
    {
2152
        if (null === $survey) {
2153
            api_not_allowed(true);
2154
        }
2155
2156
        $utcZone = new DateTimeZone('UTC');
2157
        $startDate = $survey->getAvailFrom();
2158
        $endDate = $survey->getAvailTill();
2159
        $currentDate = new DateTime('now', $utcZone);
2160
        $currentDate->modify('today');
2161
2162
        if ($currentDate < $startDate) {
2163
            api_not_allowed(
2164
                true,
2165
                Display:: return_message(
2166
                    get_lang('This survey is not yet available. Please try again later. Thank you.'),
2167
                    'warning',
2168
                    false
2169
                )
2170
            );
2171
        }
2172
2173
        if ($currentDate > $endDate) {
2174
            api_not_allowed(
2175
                true,
2176
                Display:: return_message(
2177
                    get_lang('Sorry, this survey is not available anymore. Thank you for trying.'),
2178
                    'warning',
2179
                    false
2180
                )
2181
            );
2182
        }
2183
    }
2184
2185
    /**
2186
     * @param int    $userId
2187
     * @param string $surveyCode
2188
     * @param int    $courseId
2189
     * @param int    $sessionId
2190
     * @param int    $groupId
2191
     *
2192
     * @return array|CSurveyInvitation[]
2193
     */
2194
    public static function getUserInvitationsForSurveyInCourse(
2195
        $userId,
2196
        $surveyCode,
2197
        $courseId,
2198
        $sessionId = 0,
2199
        $groupId = 0
2200
    ) {
2201
        $invitationRepo = Database::getManager()->getRepository(CSurveyInvitation::class);
2202
2203
        return $invitationRepo->findBy(
2204
            [
2205
                'user' => $userId,
2206
                'cId' => $courseId,
2207
                'sessionId' => $sessionId,
2208
                'groupId' => $groupId,
2209
                'surveyCode' => $surveyCode,
2210
            ],
2211
            ['invitationDate' => 'DESC']
2212
        );
2213
    }
2214
2215
    /**
2216
     * @param array $userInfo
2217
     * @param int   $answered (1 = answered 0 = not answered)
2218
     *
2219
     * @return string
2220
     */
2221
    public static function surveyReport($userInfo, $answered = 0)
2222
    {
2223
        $userId = isset($userInfo['user_id']) ? (int) $userInfo['user_id'] : 0;
2224
        $answered = (int) $answered;
2225
2226
        if (empty($userId)) {
2227
            return '';
2228
        }
2229
2230
        $em = Database::getManager();
2231
        $repo = $em->getRepository(CSurveyInvitation::class);
2232
        $repoSurvey = $em->getRepository(CSurvey::class);
2233
        $invitations = $repo->findBy(['user' => $userId, 'answered' => $answered]);
2234
        $mainUrl = api_get_path(WEB_CODE_PATH).'survey/survey.php?';
2235
        $content = '';
2236
2237
        if (empty($answered)) {
2238
            $content .= Display::page_subheader(get_lang('Unanswered'));
2239
        } else {
2240
            $content .= Display::page_subheader(get_lang('Answered'));
2241
        }
2242
2243
        if (!empty($invitations)) {
2244
            $table = new HTML_Table(['class' => 'table']);
2245
            $table->setHeaderContents(0, 0, get_lang('Survey name'));
2246
            $table->setHeaderContents(0, 1, get_lang('Course'));
2247
2248
            if (empty($answered)) {
2249
                $table->setHeaderContents(0, 2, get_lang('Survey').' - '.get_lang('End Date'));
2250
            }
2251
2252
            // Not answered
2253
            /** @var CSurveyInvitation $invitation */
2254
            $row = 1;
2255
            foreach ($invitations as $invitation) {
2256
                $course = $invitation->getCourse();
2257
                $courseId = $course->getId();
2258
                $courseCode = $course->getCode();
2259
                $sessionId = $invitation->getSession() ? $invitation->getSession()->getId() : 0;
2260
2261
                if (!empty($answered)) {
2262
                    // check if user is subscribed to the course/session
2263
                    if (empty($sessionId)) {
2264
                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode);
2265
                    } else {
2266
                        $subscribe = CourseManager::is_user_subscribed_in_course(
2267
                            $userId,
2268
                            $courseCode,
2269
                            true,
2270
                            $sessionId
2271
                        );
2272
                    }
2273
2274
                    // User is not subscribe skip!
2275
                    if (empty($subscribe)) {
2276
                        continue;
2277
                    }
2278
                }
2279
2280
                $survey = $invitation->getSurvey();
2281
                if (null === $survey) {
2282
                    continue;
2283
                }
2284
2285
                $url = $mainUrl.'survey_id='.$survey->getIid().'&cid='.$courseId.'&sid='.$sessionId;
2286
                $title = $survey->getTitle();
2287
                $title = Display::url($title, $url);
2288
                $courseTitle = $course->getTitle();
2289
                if (!empty($sessionId)) {
2290
                    $courseTitle .= ' ('.$invitation->getSession()->getName().')';
2291
                }
2292
2293
                $surveyData = self::get_survey($survey->getIid(), 0, $courseCode);
2294
                $table->setCellContents($row, 0, $title);
2295
                $table->setCellContents($row, 1, $courseTitle);
2296
2297
                if (empty($answered)) {
2298
                    $table->setHeaderContents(
2299
                        $row,
2300
                        2,
2301
                        api_get_local_time(
2302
                            $survey->getAvailTill(),
2303
                            null,
2304
                            null,
2305
                            true,
2306
                            false
2307
                        )
2308
                    );
2309
                }
2310
2311
                if (!empty($answered) && 0 == $survey->getAnonymous()) {
2312
                    $answers = SurveyUtil::displayCompleteReport(
2313
                        $surveyData,
2314
                        $userId,
2315
                        false,
2316
                        false,
2317
                        false
2318
                    );
2319
                    $table->setCellContents(++$row, 0, $answers);
2320
                    $table->setCellContents(++$row, 1, '');
2321
                }
2322
2323
                $row++;
2324
            }
2325
            $content .= $table->toHtml();
2326
        } else {
2327
            $content .= Display::return_message(get_lang('No data available'));
2328
        }
2329
2330
        return $content;
2331
    }
2332
2333
    public static function sendToTutors(CSurvey $survey)
2334
    {
2335
        $surveyId = $survey->getIid();
2336
2337
        $extraFieldValue = new ExtraFieldValue('survey');
2338
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
2339
        if ($groupData && !empty($groupData['value'])) {
2340
            $groupInfo = GroupManager::get_group_properties($groupData['value']);
2341
            if ($groupInfo) {
2342
                $tutors = GroupManager::getTutors($groupInfo);
2343
                if (!empty($tutors)) {
2344
                    SurveyUtil::saveInviteMail(
2345
                        $survey,
2346
                        ' ',
2347
                        ' ',
2348
                        false
2349
                    );
2350
2351
                    foreach ($tutors as $tutor) {
2352
                        $subject = sprintf(get_lang('GroupSurveyX'), $groupInfo['name']);
2353
                        $content = sprintf(
2354
                            get_lang('HelloXGroupX'),
2355
                            $tutor['complete_name'],
2356
                            $groupInfo['name']
2357
                        );
2358
2359
                        SurveyUtil::saveInvitations(
2360
                            $survey,
2361
                            ['users' => $tutor['user_id']],
2362
                            $subject,
2363
                            $content,
2364
                            false,
2365
                            true,
2366
                            false,
2367
                            true
2368
                        );
2369
                    }
2370
                    Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false));
2371
                }
2372
                SurveyUtil::updateInvitedCount($survey);
2373
2374
                return true;
2375
            }
2376
        }
2377
2378
        return false;
2379
    }
2380
}
2381