SurveyManager::moveSurveyQuestion()   B
last analyzed

Complexity

Conditions 7
Paths 16

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 20
c 0
b 0
f 0
nc 16
nop 3
dl 0
loc 28
rs 8.6666
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(string $code, ?int $surveyId = null)
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
42
            if (isset($surveyId)) {
43
                $sql = "SELECT * FROM $table
44
                    WHERE code = '$new_code' AND iid = $surveyId";
45
            } else {
46
                $sql = "SELECT * FROM $table
47
                    WHERE code = '$new_code'";
48
            }
49
50
            $result = Database::query($sql);
51
            if (Database::num_rows($result)) {
52
                $num++;
53
                $new_code = $code.$num;
54
            } else {
55
                break;
56
            }
57
        }
58
59
        return $code.$num;
60
    }
61
62
    /**
63
     * Deletes all survey invitations of a user.
64
     *
65
     * @param int $user_id
66
     *
67
     * @return bool
68
     * @assert ('') === false
69
     */
70
    public static function delete_all_survey_invitations_by_user($user_id)
71
    {
72
        $user_id = (int) $user_id;
73
        if (empty($user_id)) {
74
            return false;
75
        }
76
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
77
        $table_survey = Database::get_course_table(TABLE_SURVEY);
78
79
        $sql = "SELECT iid, survey_id
80
                FROM $table_survey_invitation WHERE user_id = '$user_id' AND c_id <> 0 ";
81
        $result = Database::query($sql);
82
        while ($row = Database::fetch_assoc($result)) {
83
            $survey_invitation_id = $row['iid'];
84
            $surveyId = $row['survey_id'];
85
            $sql2 = "DELETE FROM $table_survey_invitation
86
                     WHERE iid = '$survey_invitation_id' AND c_id <> 0";
87
            if (Database::query($sql2)) {
88
                $sql3 = "UPDATE $table_survey SET
89
                            invited = invited - 1
90
                         WHERE  iid = $surveyId";
91
                Database::query($sql3);
92
            }
93
        }
94
    }
95
96
    /**
97
     * @param string $course_code
98
     * @param int    $session_id
99
     *
100
     * @return array
101
     * @assert ('') === false
102
     */
103
    public static function get_surveys($courseCode, int $sessionId = 0)
104
    {
105
        $courseId = api_get_course_int_id();
106
        $repo = Container::getSurveyRepository();
107
        $course = api_get_course_entity($courseId);
108
        $session = api_get_session_entity($sessionId);
109
110
        $qb = $repo->getResourcesByCourse($course, $session, null, null, true, true);
111
112
        return $qb->getQuery()->getArrayResult();
113
    }
114
115
    /**
116
     * Retrieves all the survey information.
117
     *
118
     * @param int $survey_id the id of the survey
119
     * @param int $shared    this parameter determines if
120
     *                       we have to get the information of a survey from the central (shared) database or from the
121
     *                       course database
122
     * @param string course code optional
123
     *
124
     * @author Patrick Cool <[email protected]>, Ghent University
125
     *
126
     * @version February 2007
127
     * @assert ('') === false
128
     *
129
     * @return array
130
     *
131
     * @todo this is the same function as in create_new_survey.php
132
     */
133
    public static function get_survey(
134
        $survey_id,
135
        $shared = 0,
136
        $course_code = '',
137
        $simple_return = false
138
    ) {
139
        $courseInfo = api_get_course_info();
140
        $survey_id = (int) $survey_id;
141
        $table_survey = Database::get_course_table(TABLE_SURVEY);
142
143
        if (empty($courseInfo)) {
144
            return [];
145
        }
146
        $sql = "SELECT * FROM $table_survey
147
                WHERE iid = $survey_id";
148
149
        $result = Database::query($sql);
150
        $return = [];
151
152
        if (Database::num_rows($result) > 0) {
153
            $return = Database::fetch_assoc($result);
154
            if ($simple_return) {
155
                return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return also could return the type boolean which is incompatible with the documented return type array.
Loading history...
156
            }
157
            // We do this (temporarily) to have the array match the quickform elements immediately
158
            // idealiter the fields in the db match the quickform fields
159
            $return['survey_code'] = $return['code'];
160
            $return['survey_title'] = $return['title'];
161
            $return['survey_subtitle'] = $return['subtitle'];
162
            $return['survey_language'] = $return['lang'];
163
            $return['start_date'] = $return['avail_from'];
164
            $return['end_date'] = $return['avail_till'];
165
            $return['survey_share'] = $return['is_shared'];
166
            $return['survey_introduction'] = $return['intro'];
167
            $return['survey_thanks'] = $return['surveythanks'];
168
            $return['survey_type'] = $return['survey_type'];
169
            $return['one_question_per_page'] = $return['one_question_per_page'];
170
            $return['show_form_profile'] = $return['show_form_profile'];
171
            $return['input_name_list'] = isset($return['input_name_list']) ? $return['input_name_list'] : null;
172
            $return['shuffle'] = $return['shuffle'];
173
            $return['parent_id'] = $return['parent_id'];
174
            $return['survey_version'] = $return['survey_version'];
175
            $return['anonymous'] = $return['anonymous'];
176
            $return['c_id'] = isset($return['c_id']) ? $return['c_id'] : 0;
177
            $return['session_id'] = isset($return['session_id']) ? $return['session_id'] : 0;
178
        }
179
180
        return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return also could return the type boolean which is incompatible with the documented return type array.
Loading history...
181
    }
182
183
    /**
184
     * @param string $code
185
     *
186
     * @return string
187
     */
188
    public static function generateSurveyCode($code)
189
    {
190
        return strtolower(CourseManager::generate_course_code($code));
191
    }
192
193
    /**
194
     * This function stores a survey in the database.
195
     *
196
     * @param array $values
197
     *
198
     * @return array $return the type of return message that has to be displayed and the message in it
199
     *
200
     * @author Patrick Cool <[email protected]>, Ghent University
201
     *
202
     * @version February 2007
203
     */
204
    public static function store_survey($values)
205
    {
206
        $session_id = api_get_session_id();
207
        $courseCode = api_get_course_id();
208
        $table_survey = Database::get_course_table(TABLE_SURVEY);
209
        $shared_survey_id = 0;
210
        $displayQuestionNumber = isset($values['display_question_number']);
211
        $repo = Container::getSurveyRepository();
212
213
        if (!isset($values['survey_id'])) {
214
            // Check if the code doesn't soon exists in this language
215
            $sql = 'SELECT 1 FROM '.$table_survey.'
216
			        WHERE
217
			            code = "'.Database::escape_string($values['survey_code']).'" AND
218
			            lang = "'.Database::escape_string($values['survey_language']).'"';
219
            $rs = Database::query($sql);
220
            if (Database::num_rows($rs) > 0) {
221
                Display::addFlash(
222
                    Display::return_message(
223
                        get_lang('This survey code soon exists in this language'),
224
                        'error'
225
                    )
226
                );
227
                $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...
228
                $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0;
229
230
                return $return;
231
            }
232
233
            if (!isset($values['anonymous'])) {
234
                $values['anonymous'] = 0;
235
            }
236
237
            $values['anonymous'] = (int) $values['anonymous'];
238
239
            $survey = new CSurvey();
240
            $extraParams = [];
241
            if (0 == $values['anonymous']) {
242
                // Input_name_list
243
                $values['show_form_profile'] = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0;
244
                $survey->setShowFormProfile($values['show_form_profile']);
245
246
                if (1 == $values['show_form_profile']) {
247
                    // Input_name_list
248
                    $fields = explode(',', $values['input_name_list']);
249
                    $field_values = '';
250
                    foreach ($fields as &$field) {
251
                        if ('' != $field) {
252
                            if ('' == $values[$field]) {
253
                                $values[$field] = 0;
254
                            }
255
                            $field_values .= $field.':'.$values[$field].'@';
256
                        }
257
                    }
258
                    $extraParams['form_fields'] = $field_values;
259
                } else {
260
                    $extraParams['form_fields'] = '';
261
                }
262
                $survey->setFormFields($extraParams['form_fields']);
263
            }
264
265
            $extraParams['one_question_per_page'] = isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0;
266
            $extraParams['shuffle'] = isset($values['shuffle']) ? $values['shuffle'] : 0;
267
268
            if (1 == $values['survey_type']) {
269
                $survey
270
                    ->setSurveyType(1)
271
                    ->setShuffle($values['shuffle'])
272
                    ->setOneQuestionPerPage($values['one_question_per_page'])
273
                ;
274
                // Logic for versioning surveys
275
                if (!empty($values['parent_id'])) {
276
                    $parentId = (int) $values['parent_id'];
277
                    $sql = 'SELECT survey_version
278
                            FROM '.$table_survey.'
279
					        WHERE
280
					            parent_id = '.$parentId.'
281
                            ORDER BY survey_version DESC
282
                            LIMIT 1';
283
                    $rs = Database::query($sql);
284
                    if (0 === Database::num_rows($rs)) {
285
                        $sql = 'SELECT survey_version FROM '.$table_survey.'
286
						        WHERE
287
						            iid = '.$parentId;
288
                        $rs = Database::query($sql);
289
                        $getversion = Database::fetch_assoc($rs);
290
                        if (empty($getversion['survey_version'])) {
291
                            $versionValue = ++$getversion['survey_version'];
292
                        } else {
293
                            $versionValue = $getversion['survey_version'];
294
                        }
295
                    } else {
296
                        $row = Database::fetch_assoc($rs);
297
                        $pos = api_strpos($row['survey_version'], '.');
298
                        if (false === $pos) {
299
                            $row['survey_version'] = $row['survey_version'] + 1;
300
                            $versionValue = $row['survey_version'];
301
                        } else {
302
                            $getlast = explode('\.', $row['survey_version']);
303
                            $lastversion = array_pop($getlast);
304
                            $lastversion = $lastversion + 1;
305
                            $add = implode('.', $getlast);
306
                            if ('' != $add) {
307
                                $insertnewversion = $add.'.'.$lastversion;
308
                            } else {
309
                                $insertnewversion = $lastversion;
310
                            }
311
                            $versionValue = $insertnewversion;
312
                        }
313
                    }
314
                    $survey->setSurveyVersion($versionValue);
315
                }
316
            }
317
318
            $course = api_get_course_entity();
319
            $session = api_get_session_entity();
320
321
            $survey
322
                ->setCode(self::generateSurveyCode($values['survey_code']))
323
                ->setTitle($values['survey_title'])
324
                ->setSubtitle($values['survey_title'])
325
                ->setLang($values['survey_language'])
326
                ->setAvailFrom(new \DateTime($values['start_date']))
327
                ->setAvailTill(new \DateTime($values['end_date']))
328
                ->setIsShared($shared_survey_id)
329
                ->setTemplate('template')
330
                ->setIntro($values['survey_introduction'])
331
                ->setSurveyThanks($values['survey_thanks'])
332
                ->setDisplayQuestionNumber($displayQuestionNumber)
333
                ->setAnonymous((string) $values['anonymous'])
334
                ->setVisibleResults((int) $values['visible_results'])
335
                ->setSurveyType((int) ($values['survey_type'] ?? 1))
336
                ->setParent($course)
337
                ->addCourseLink($course, $session)
338
            ;
339
340
            if (isset($values['parent_id']) && !empty($values['parent_id'])) {
341
                $parent = $repo->find($values['parent_id']);
342
                $survey->setSurveyParent($parent);
343
            }
344
345
            $repo->create($survey);
346
347
            $survey_id = $survey->getIid();
348
            if ($survey_id > 0) {
349
                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

349
                Event::/** @scrutinizer ignore-call */ 
350
                       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...
350
                    LOG_SURVEY_CREATED,
351
                    LOG_SURVEY_ID,
352
                    $survey_id,
353
                    null,
354
                    api_get_user_id(),
355
                    api_get_course_int_id(),
356
                    api_get_session_id()
357
                );
358
            }
359
360
            if (1 == $values['survey_type'] && !empty($values['parent_id'])) {
361
                self::copySurvey($values['parent_id'], $survey_id);
362
            }
363
364
            Display::addFlash(
365
                Display::return_message(
366
                    get_lang('The survey has been created succesfully'),
367
                    'success'
368
                )
369
            );
370
            $return['id'] = $survey_id;
371
        } else {
372
            // Check whether the code doesn't soon exists in this language
373
            $sql = 'SELECT 1 FROM '.$table_survey.'
374
			        WHERE
375
			            code = "'.Database::escape_string($values['survey_code']).'" AND
376
			            lang = "'.Database::escape_string($values['survey_language']).'" AND
377
			            iid !='.intval($values['survey_id']);
378
            $rs = Database::query($sql);
379
            if (Database::num_rows($rs) > 0) {
380
                Display::addFlash(
381
                    Display::return_message(
382
                        get_lang('This survey code soon exists in this language'),
383
                        'error'
384
                    )
385
                );
386
                $return['type'] = 'error';
387
                $return['id'] = isset($values['survey_id']) ? $values['survey_id'] : 0;
388
389
                return $return;
390
            }
391
392
            if (!isset($values['anonymous'])
393
                || (isset($values['anonymous']) && '' == $values['anonymous'])
394
            ) {
395
                $values['anonymous'] = 0;
396
            }
397
398
            /** @var CSurvey $survey */
399
            $survey = $repo->find($values['survey_id']);
400
401
            $survey->setOneQuestionPerPage(isset($values['one_question_per_page']) ? $values['one_question_per_page'] : 0);
402
            $survey->setShuffle(isset($values['shuffle']) ? $values['shuffle'] : 0);
403
404
            if (0 == $values['anonymous']) {
405
                $survey->setShowFormProfile(isset($values['show_form_profile']) ? $values['show_form_profile'] : 0);
406
                $isFormProfile = isset($values['show_form_profile']) ? $values['show_form_profile'] : 0;
407
                if (1 == $isFormProfile) {
408
                    $fields = explode(',', $values['input_name_list']);
409
                    $field_values = '';
410
                    foreach ($fields as &$field) {
411
                        if ('' != $field) {
412
                            if (!isset($values[$field]) ||
413
                                (isset($values[$field]) && '' == $values[$field])
414
                            ) {
415
                                $values[$field] = 0;
416
                            }
417
                            $field_values .= $field.':'.$values[$field].'@';
418
                        }
419
                    }
420
                    $survey->setFormFields($field_values);
421
                } else {
422
                    $survey->setFormFields('');
423
                }
424
            } else {
425
                $survey->setFormFields('');
426
                $survey->setShowFormProfile(0);
427
            }
428
429
            $survey
430
                ->setTitle($values['survey_title'])
431
                ->setSubtitle($values['survey_title'])
432
                ->setLang($values['survey_language'])
433
                ->setAvailFrom(new \DateTime($values['start_date']))
434
                ->setAvailTill(new \DateTime($values['end_date']))
435
                ->setIsShared($shared_survey_id)
436
                ->setTemplate('template')
437
                ->setIntro($values['survey_introduction'])
438
                ->setSurveyThanks($values['survey_thanks'])
439
                ->setAnonymous((string) $values['anonymous'])
440
                ->setVisibleResults((int) $values['visible_results'])
441
                ->setDisplayQuestionNumber($displayQuestionNumber)
442
            ;
443
444
            $repo->update($survey);
445
            /*
446
            // Update into item_property (update)
447
            api_item_property_update(
448
                api_get_course_info(),
449
                TOOL_SURVEY,
450
                $values['survey_id'],
451
                'SurveyUpdated',
452
                api_get_user_id()
453
            );*/
454
455
            Display::addFlash(
456
                Display::return_message(
457
                    get_lang('The survey has been updated succesfully'),
458
                    'confirmation'
459
                )
460
            );
461
462
            $return['id'] = $values['survey_id'];
463
        }
464
465
        $survey_id = (int) $return['id'];
466
467
        // Gradebook
468
        $gradebook_option = false;
469
        if (isset($values['survey_qualify_gradebook'])) {
470
            $gradebook_option = $values['survey_qualify_gradebook'] > 0;
471
        }
472
473
        $gradebook_link_type = 8;
474
        $link_info = GradebookUtils::isResourceInCourseGradebook(
475
            api_get_course_int_id(),
476
            $gradebook_link_type,
477
            $survey_id,
478
            $session_id
479
        );
480
481
        $gradebook_link_id = isset($link_info['id']) ? $link_info['id'] : false;
482
483
        if ($gradebook_option) {
484
            if ($survey_id > 0) {
485
                $title_gradebook = ''; // Not needed here.
486
                $description_gradebook = ''; // Not needed here.
487
                $survey_weight = floatval($_POST['survey_weight']);
488
                $max_score = 1;
489
490
                if (!$gradebook_link_id && isset($values['category_id'])) {
491
                    GradebookUtils::add_resource_to_course_gradebook(
492
                        $values['category_id'],
493
                        api_get_course_int_id(),
494
                        $gradebook_link_type,
495
                        $survey_id,
496
                        $title_gradebook,
497
                        $survey_weight,
498
                        $max_score,
499
                        $description_gradebook,
500
                        1,
501
                        $session_id
502
                    );
503
                } else {
504
                    GradebookUtils::updateResourceFromCourseGradebook(
505
                        $gradebook_link_id,
506
                        api_get_course_int_id(),
507
                        $survey_weight
508
                    );
509
                }
510
            }
511
        } else {
512
            // Delete everything of the gradebook for this $linkId
513
            GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id);
514
        }
515
516
        return $return;
517
    }
518
519
    public static function deleteSurvey(CSurvey $survey)
520
    {
521
        $repo = Container::getSurveyRepository();
522
        $surveyId = $survey->getIid();
523
        $repo->delete($survey);
524
525
        $table_survey = Database::get_course_table(TABLE_SURVEY);
526
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
527
528
        Event::addEvent(
529
            LOG_SURVEY_DELETED,
530
            LOG_SURVEY_ID,
531
            $surveyId,
532
            null,
533
            api_get_user_id(),
534
            api_get_course_int_id(),
535
            api_get_session_id()
536
        );
537
538
        /*// Deleting groups of this survey
539
        $sql = "DELETE FROM $table_survey_question_group
540
                WHERE c_id = $course_id AND iid='".$survey_id."'";
541
        Database::query($sql);*/
542
543
        // Deleting the questions of the survey
544
        self::delete_all_survey_questions($surveyId, false);
545
546
        // Update into item_property (delete)
547
        /*api_item_property_update(
548
            $course_info,
549
            TOOL_SURVEY,
550
            $survey_id,
551
            'SurveyDeleted',
552
            api_get_user_id()
553
        );*/
554
555
        SkillModel::deleteSkillsFromItem($surveyId, ITEM_TYPE_SURVEY);
556
557
        return true;
558
    }
559
560
    /**
561
     * Copy given survey to a new (optional) given survey ID.
562
     */
563
    public static function copySurvey(
564
        int $surveyId,
565
        ?int $newSurveyId = null,
566
        ?int $targetCourseId = null,
567
        ?int $targetSessionId = null
568
    ): ?int {
569
        $originalCourseId = api_get_course_int_id();
570
        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...
571
            $targetCourseId = $originalCourseId;
572
        }
573
574
        $repo = Container::getSurveyRepository();
575
576
        $surveyTable = Database::get_course_table(TABLE_SURVEY);
577
        $surveyQuestionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
578
        $surveyOptionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
579
580
        $surveyData = self::get_survey($surveyId, 0, null, true);
581
        if (empty($surveyData)) {
582
            return null;
583
        }
584
585
        if (empty($newSurveyId)) {
586
            $surveyData['code'] = self::generate_unique_code($surveyData['code']);
587
            $surveyData['session_id'] = $targetSessionId ?? api_get_session_id();
588
589
            if ($targetCourseId === $originalCourseId) {
590
                $surveyData['title'] .= ' '.get_lang('Copy');
591
            }
592
593
            unset($surveyData['iid'], $surveyData['id']);
594
595
            if ($targetSessionId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $targetSessionId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
596
                $newSurveyId = Database::insert($surveyTable, $surveyData);
597
            } else {
598
                $course = api_get_course_entity();
599
                $session = api_get_session_entity();
600
601
                $survey = new CSurvey();
602
                $survey
603
                    ->setSurveyType($surveyData['survey_type'])
604
                    ->setSurveyVersion($surveyData['survey_version'])
605
                    ->setCode($surveyData['code'])
606
                    ->setTitle($surveyData['title'])
607
                    ->setSubtitle($surveyData['subtitle'])
608
                    ->setLang($surveyData['lang'])
609
                    ->setAvailFrom(new \DateTime($surveyData['avail_from']))
610
                    ->setAvailTill(new \DateTime($surveyData['avail_till']))
611
                    ->setIsShared($surveyData['is_shared'])
612
                    ->setTemplate($surveyData['template'])
613
                    ->setIntro($surveyData['intro'])
614
                    ->setSurveyThanks($surveyData['surveythanks'])
615
                    ->setAnonymous($surveyData['anonymous'])
616
                    ->setVisibleResults($surveyData['visible_results'])
617
                    ->setShuffle($surveyData['shuffle'])
618
                    ->setOneQuestionPerPage($surveyData['one_question_per_page'])
619
                    ->setShowFormProfile($surveyData['show_form_profile'])
620
                    ->setFormFields($surveyData['form_fields'])
621
                    ->setParent($course)
622
                    ->addCourseLink($course, $session);
623
624
                if (!empty($surveyData['parent_id'])) {
625
                    $parent = $repo->find($surveyData['parent_id']);
626
                    if ($parent) {
627
                        $survey->setSurveyParent($parent);
628
                    }
629
                }
630
631
                $repo->create($survey);
632
                $newSurveyId = $survey->getIid();
633
            }
634
        }
635
636
        if (empty($newSurveyId)) {
637
            return null;
638
        }
639
640
        $sql = "SELECT * FROM $surveyQuestionTable WHERE survey_id = $surveyId";
641
        $res = Database::query($sql);
642
        $question_id = [];
643
        while ($row = Database::fetch_assoc($res)) {
644
            $params = [
645
                'survey_id' => $newSurveyId,
646
                'survey_question' => $row['survey_question'],
647
                'survey_question_comment' => $row['survey_question_comment'],
648
                'type' => $row['type'],
649
                'display' => $row['display'],
650
                'sort' => $row['sort'],
651
                'shared_question_id' => $row['shared_question_id'],
652
                'max_value' => $row['max_value'],
653
                'survey_group_pri' => $row['survey_group_pri'],
654
                'survey_group_sec1' => $row['survey_group_sec1'],
655
                'survey_group_sec2' => $row['survey_group_sec2'],
656
            ];
657
658
            if (isset($row['is_required'])) {
659
                $params['is_required'] = $row['is_required'];
660
            }
661
662
            $insertId = Database::insert($surveyQuestionTable, $params);
663
            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...
664
                $question_id[$row['iid']] = $insertId;
665
            }
666
        }
667
668
        $sql = "SELECT * FROM $surveyOptionsTable WHERE survey_id = $surveyId";
669
        $res = Database::query($sql);
670
        while ($row = Database::fetch_assoc($res)) {
671
            $params = [
672
                'question_id' => $question_id[$row['question_id']] ?? 0,
673
                'survey_id' => $newSurveyId,
674
                'option_text' => $row['option_text'],
675
                'sort' => $row['sort'],
676
                'value' => $row['value'],
677
            ];
678
            Database::insert($surveyOptionsTable, $params);
679
        }
680
681
        return $newSurveyId;
682
    }
683
684
    /**
685
     * This function duplicates a survey (and also all the question in that survey.
686
     *
687
     * @param int $surveyId id of the survey that has to be duplicated
688
     * @param int $courseId id of the course which survey has to be duplicated
689
     *
690
     * @return true
691
     *
692
     * @author Eric Marguin <[email protected]>, Elixir Interactive
693
     *
694
     * @version October 2007
695
     */
696
    public static function empty_survey($surveyId, $courseId = 0)
697
    {
698
        // Database table definitions
699
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
700
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
701
        $table_survey = Database::get_course_table(TABLE_SURVEY);
702
703
        $courseId = (int) $courseId;
704
        $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
705
        $surveyId = (int) $surveyId;
706
707
        $datas = self::get_survey($surveyId);
708
        $session_where = '';
709
        if (0 != api_get_session_id()) {
710
            $session_where = ' AND session_id = "'.api_get_session_id().'" ';
711
        }
712
713
        $sql = 'DELETE FROM '.$table_survey_invitation.'
714
		        WHERE
715
		            survey_id = "'.$surveyId.'" '.$session_where.' ';
716
        Database::query($sql);
717
718
        $sql = 'DELETE FROM '.$table_survey_answer.'
719
		        WHERE
720
		        survey_id = "'.$surveyId.'" '.$session_where.' ';
721
        Database::query($sql);
722
723
        $sql = 'UPDATE '.$table_survey.' SET invited=0, answered=0
724
		        WHERE iid ='.$surveyId;
725
        Database::query($sql);
726
727
        Event::addEvent(
728
            LOG_SURVEY_CLEAN_RESULTS,
729
            LOG_SURVEY_ID,
730
            $surveyId,
731
            null,
732
            api_get_user_id(),
733
            api_get_course_int_id(),
734
            api_get_session_id()
735
        );
736
737
        return true;
738
    }
739
740
    /**
741
     * Updates c_survey.answered: number of people who have taken the survey (=filled at least one question).
742
     */
743
    public static function updateSurveyAnswered(CSurvey $survey, $user, $lpItemId = 0): void
744
    {
745
        $em = Database::getManager();
746
        $surveyId = $survey->getIid();
747
        $courseId = api_get_course_int_id();
748
        $sessionId = api_get_session_id();
749
750
        $survey->setAnswered($survey->getAnswered() + 1);
751
        $em->persist($survey);
752
        $em->flush();
753
754
        $lpItemCondition = '';
755
        if (!empty($lpItemId)) {
756
            $lpItemCondition = " AND c_lp_item_id = $lpItemId";
757
        }
758
        $sessionCondition = '';
759
        if (true === api_get_configuration_value('show_surveys_base_in_sessions')) {
760
            $sessionCondition = api_get_session_condition($sessionId);
761
        }
762
763
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
764
        // Storing that the user has finished the survey.
765
        $sql = "UPDATE $table
766
                SET
767
                    answered_at = '".api_get_utc_datetime()."',
768
                    answered = 1
769
                WHERE
770
                    session_id = $sessionId AND
771
                    user_id ='".Database::escape_string($user)."' AND
772
                    survey_id ='".$surveyId."'
773
                    $sessionCondition
774
                    $lpItemCondition";
775
        Database::query($sql);
776
    }
777
778
    /**
779
     * This function return the "icon" of the question type.
780
     *
781
     * @param string $type
782
     *
783
     * @author Patrick Cool <[email protected]>, Ghent University
784
     *
785
     * @version February 2007
786
     */
787
    public static function icon_question($type)
788
    {
789
        // the possible question types
790
        $possible_types = [
791
            'personality',
792
            'yesno',
793
            'multiplechoice',
794
            'multipleresponse',
795
            'open',
796
            'dropdown',
797
            'comment',
798
            'pagebreak',
799
            'percentage',
800
            'score',
801
        ];
802
803
        // the images array
804
        $icon_question = [
805
            'yesno' => 'thumbs-up-down',
806
            'personality' => 'thumbs-up-down',
807
            'multiplechoice' => 'format-list-bulleted',
808
            'multipleresponse' => 'format-list-bulleted-square',
809
            'open' => 'form-textarea',
810
            'dropdown' => 'form-dropdown',
811
            'percentage' => 'percent-box-outline',
812
            'score' => 'format-annotation-plus',
813
            'comment' => 'format-align-top',
814
            'pagebreak' => 'format-page-break',
815
        ];
816
817
        if (in_array($type, $possible_types)) {
818
            return $icon_question[$type];
819
        }
820
821
        return false;
822
    }
823
824
    /**
825
     * This function retrieves all the information of a question.
826
     *
827
     * @param int  $question_id the id of the question
828
     * @param bool $shared
829
     *
830
     * @return array
831
     *
832
     * @author Patrick Cool <[email protected]>, Ghent University
833
     *
834
     * @version January 2007
835
     *
836
     * @todo one sql call should do the trick
837
     */
838
    public static function get_question($question_id)
839
    {
840
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
841
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
842
        $course_id = api_get_course_int_id();
843
        $question_id = (int) $question_id;
844
845
        if (empty($question_id)) {
846
            return [];
847
        }
848
849
        $sql = "SELECT * FROM $tbl_survey_question
850
                WHERE iid = $question_id
851
                ORDER BY `sort` ";
852
853
        $sqlOption = "  SELECT * FROM $table_survey_question_option
854
                        WHERE question_id='".$question_id."'
855
                        ORDER BY `sort` ";
856
        // Getting the information of the question
857
        $result = Database::query($sql);
858
        $row = Database::fetch_assoc($result);
859
860
        $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...
861
        $return['parent_id'] = isset($row['parent_id']) ? $row['parent_id'] : 0;
862
        $return['parent_option_id'] = isset($row['parent_option_id']) ? $row['parent_option_id'] : 0;
863
        $return['question_id'] = $row['iid'];
864
        $return['type'] = $row['type'];
865
        $return['question'] = $row['survey_question'];
866
        $return['horizontalvertical'] = $row['display'];
867
        $return['shared_question_id'] = $row['shared_question_id'];
868
        $return['maximum_score'] = $row['max_value'];
869
        $return['is_required'] = $row['is_required'];
870
871
        if (0 != $row['survey_group_pri']) {
872
            $return['assigned'] = $row['survey_group_pri'];
873
            $return['choose'] = 1;
874
        } else {
875
            $return['assigned1'] = $row['survey_group_sec1'];
876
            $return['assigned2'] = $row['survey_group_sec2'];
877
            $return['choose'] = 2;
878
        }
879
880
        // Getting the information of the question options
881
        $result = Database::query($sqlOption);
882
        $counter = 0;
883
        while ($row = Database::fetch_assoc($result)) {
884
            /** @todo this should be renamed to options instead of answers */
885
            $return['answers'][] = $row['option_text'];
886
            $return['values'][] = $row['value'];
887
            $return['answer_data'][$counter]['data'] = $row['option_text'];
888
            $return['answer_data'][$counter]['iid'] = $row['iid'];
889
            /** @todo this can be done more elegantly (used in reporting) */
890
            $return['answersid'][] = $row['iid'];
891
            $counter++;
892
        }
893
894
        return $return;
895
    }
896
897
    /**
898
     * This function gets all the question of any given survey.
899
     *
900
     * @param int $surveyId the id of the survey
901
     * @param int $courseId
902
     *
903
     * @return array containing all the questions of the survey
904
     *
905
     * @author Patrick Cool <[email protected]>, Ghent University
906
     *
907
     * @version February 2007
908
     *
909
     * @todo one sql call should do the trick
910
     */
911
    public static function get_questions($surveyId, $courseId = 0)
912
    {
913
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
914
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
915
916
        $courseId = (int) $courseId;
917
        $surveyId = (int) $surveyId;
918
919
        // Getting the information of the question
920
        $sql = "SELECT * FROM $tbl_survey_question
921
		        WHERE survey_id= $surveyId ";
922
        $result = Database::query($sql);
923
        $questions = [];
924
        while ($row = Database::fetch_assoc($result)) {
925
            $questionId = $row['iid'];
926
            $questions[$questionId]['survey_id'] = $surveyId;
927
            $questions[$questionId]['question_id'] = $questionId;
928
            $questions[$questionId]['type'] = $row['type'];
929
            $questions[$questionId]['question'] = $row['survey_question'];
930
            $questions[$questionId]['horizontalvertical'] = $row['display'];
931
            $questions[$questionId]['maximum_score'] = $row['max_value'];
932
            $questions[$questionId]['sort'] = $row['sort'];
933
            $questions[$questionId]['survey_question_comment'] = $row['survey_question_comment'];
934
935
            // Getting the information of the question options
936
            $sql = "SELECT * FROM $table_survey_question_option
937
		             WHERE survey_id= $surveyId  AND question_id = $questionId";
938
            $resultOptions = Database::query($sql);
939
            while ($rowOption = Database::fetch_assoc($resultOptions)) {
940
                $questions[$questionId]['answers'][] = $rowOption['option_text'];
941
            }
942
        }
943
944
        return $questions;
945
    }
946
947
    public static function saveQuestion(CSurvey $survey, array $form_content, bool $showMessage = true, array $dataFromDatabase = [])
948
    {
949
        $surveyId = $survey->getIid();
950
951
        $error = false;
952
        $message = '';
953
        if (strlen($form_content['question']) > 1) {
954
            // Checks length of the question
955
            $empty_answer = false;
956
            if (1 == $survey->getSurveyType()) {
957
                if (empty($form_content['choose'])) {
958
                    return 'PleaseChooseACondition';
959
                }
960
961
                if ((2 == $form_content['choose']) &&
962
                    ($form_content['assigned1'] == $form_content['assigned2'])
963
                ) {
964
                    return 'ChooseDifferentCategories';
965
                }
966
            }
967
968
            if ('percentage' !== $form_content['type']) {
969
                if (isset($form_content['answers'])) {
970
                    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...
971
                        if (strlen($form_content['answers'][$i]) < 1) {
972
                            $empty_answer = true;
973
                            break;
974
                        }
975
                    }
976
                }
977
            }
978
979
            if ('score' === $form_content['type']) {
980
                if (strlen($form_content['maximum_score']) < 1) {
981
                    $empty_answer = true;
982
                }
983
            }
984
985
            $em = Database::getManager();
986
            $course_id = api_get_course_int_id();
987
            if (!$empty_answer) {
988
                // Table definitions
989
                $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
990
991
                // Getting all the information of the survey
992
                $survey_data = self::get_survey($surveyId);
993
994
                // Storing a new question
995
                if (empty($form_content['question_id']) || !is_numeric($form_content['question_id'])) {
996
                    // Finding the max sort order of the questions in the given survey
997
                    $sql = "SELECT max(sort) AS max_sort
998
					        FROM $tbl_survey_question
999
                            WHERE survey_id = $surveyId ";
1000
                    $result = Database::query($sql);
1001
                    $row = Database::fetch_assoc($result);
1002
                    $max_sort = $row['max_sort'];
1003
1004
                    $question = new CSurveyQuestion();
1005
1006
                    // Some variables defined for survey-test type
1007
                    if (isset($_POST['choose'])) {
1008
                        if (1 == $_POST['choose']) {
1009
                            $question->setSurveyGroupPri($_POST['assigned']);
1010
                        } elseif (2 == $_POST['choose']) {
1011
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1012
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1013
                        }
1014
                    }
1015
1016
                    $question
1017
                        ->setSurveyQuestionComment($form_content['question_comment'] ?? '')
1018
                        ->setMaxValue($form_content['maximum_score'] ?? 0)
1019
                        ->setDisplay($form_content['horizontalvertical'] ?? '')
1020
                        //->setCId($course_id)
1021
                        ->setSurvey($survey)
1022
                        ->setSurveyQuestion($form_content['question'])
1023
                        ->setType($form_content['type'])
1024
                        ->setSort($max_sort + 1)
1025
                        ->setSharedQuestionId((int) $form_content['shared_question_id'])
1026
                    ;
1027
1028
                    $question->setIsMandatory(isset($form_content['is_required']));
1029
1030
                    $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...
1031
                    $params['parent_option_id'] = 0;
1032
                    if (isset($form_content['parent_id']) &&
1033
                        isset($form_content['parent_option_id']) &&
1034
                        !empty($form_content['parent_id']) &&
1035
                        !empty($form_content['parent_option_id'])
1036
                    ) {
1037
                        $params['parent_id'] = $form_content['parent_id'];
1038
                        $params['parent_option_id'] = $form_content['parent_option_id'];
1039
                    }
1040
1041
                    $em->persist($question);
1042
                    $em->flush();
1043
1044
                    $question_id = $question->getIid();
1045
                    if ($question_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $question_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1046
                        /*$sql = "UPDATE $tbl_survey_question SET question_id = $question_id
1047
                                WHERE iid = $question_id";
1048
                        Database::query($sql);*/
1049
                        $form_content['question_id'] = $question_id;
1050
                        $message = 'The question has been added.';
1051
                        $error = false;
1052
                    }
1053
                } else {
1054
                    $repo = $em->getRepository(CSurveyQuestion::class);
1055
                    $repoOption = $em->getRepository(CSurveyQuestionOption::class);
1056
                    /** @var CSurveyQuestion $question */
1057
                    $question = $repo->find($form_content['question_id']);
1058
1059
                    if (isset($_POST['choose'])) {
1060
                        if (1 == $_POST['choose']) {
1061
                            $question->setSurveyGroupPri($_POST['assigned']);
1062
                            $question->setSurveyGroupSec1(0);
1063
                            $question->setSurveyGroupSec2(0);
1064
                        } elseif (2 == $_POST['choose']) {
1065
                            $question->setSurveyGroupPri(0);
1066
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1067
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1068
                        }
1069
                    }
1070
1071
                    $maxScore = isset($form_content['maximum_score']) ? (int) $form_content['maximum_score'] : 0;
1072
                    $questionComment = $form_content['question_comment'] ?? '';
1073
                    $question
1074
                        ->setSurveyQuestionComment($questionComment)
1075
                        ->setSurveyQuestion($form_content['question'])
1076
                        ->setDisplay($form_content['horizontalvertical'])
1077
                        ->setMaxValue($maxScore)
1078
                    ;
1079
1080
                    $question->isMandatory(isset($form_content['is_required']));
1081
                    $params['parent_id'] = 0;
1082
                    $params['parent_option_id'] = 0;
1083
                    if (isset($form_content['parent_id']) &&
1084
                        isset($form_content['parent_option_id']) &&
1085
                        !empty($form_content['parent_id']) &&
1086
                        !empty($form_content['parent_option_id'])
1087
                    ) {
1088
                        $question->setParent($repo->find($form_content['parent_id']));
1089
                        $question->setParentOption($repoOption->find($form_content['parent_option_id']));
1090
                    }
1091
1092
                    $em->persist($question);
1093
                    $em->flush();
1094
                    $message = 'QuestionUpdated';
1095
                    $error = false;
1096
                }
1097
                // Storing the options of the question
1098
                self::saveQuestionOptions($survey, $question, $form_content, $dataFromDatabase);
1099
            } else {
1100
                $message = 'PleasFillAllAnswer';
1101
                $error = true;
1102
            }
1103
        } else {
1104
            $message = 'PleaseEnterAQuestion';
1105
            $error = true;
1106
        }
1107
1108
        if ($showMessage) {
1109
            if (!empty($message)) {
1110
                Display::addFlash(Display::return_message(get_lang($message)));
1111
            }
1112
        }
1113
        $result = [
1114
            'error' => $error,
1115
            'message' => $message,
1116
        ];
1117
1118
        return $result;
1119
    }
1120
1121
    /**
1122
     * Moves a survey question within the ordered list.
1123
     *
1124
     * @param string $direction The direction to move the question ('moveup' or 'movedown').
1125
     * @param int    $surveyQuestionId The ID of the survey question to move.
1126
     * @param int    $surveyId The ID of the survey to which the question belongs.
1127
     */
1128
    public static function moveSurveyQuestion(string $direction, int $surveyQuestionId, int $surveyId): void
1129
    {
1130
        $em = Database::getManager();
1131
        $repo = $em->getRepository(CSurveyQuestion::class);
1132
        $sortDirection = $direction === 'moveup' ? 'DESC' : 'ASC';
1133
        $questions = $repo->findBy(['survey' => $surveyId], ['sort' => $sortDirection]);
1134
1135
        $found = false;
1136
        foreach ($questions as $question) {
1137
            if ($found) {
1138
                $secondQuestion = $question;
1139
                $found = false;
1140
                break;
1141
            }
1142
            if ($question->getIid() == $surveyQuestionId) {
1143
                $found = true;
1144
                $firstQuestion = $question;
1145
            }
1146
        }
1147
1148
        if (isset($firstQuestion) && isset($secondQuestion)) {
1149
            $tempSort = $firstQuestion->getSort();
1150
            $firstQuestion->setSort($secondQuestion->getSort());
1151
            $secondQuestion->setSort($tempSort);
1152
1153
            $em->persist($firstQuestion);
1154
            $em->persist($secondQuestion);
1155
            $em->flush();
1156
        }
1157
    }
1158
1159
    /**
1160
     * This function deletes all the questions of a given survey
1161
     * This function is normally only called when a survey is deleted.
1162
     *
1163
     * @param int $survey_id the id of the survey that has to be deleted
1164
     *
1165
     * @return bool
1166
     *
1167
     * @author Patrick Cool <[email protected]>, Ghent University
1168
     *
1169
     * @version January 2007
1170
     */
1171
    public static function delete_all_survey_questions($survey_id, $shared = false)
1172
    {
1173
        $course_id = api_get_course_int_id();
1174
        $survey_id = (int) $survey_id;
1175
1176
        /*$sql = "DELETE FROM $table_survey_question
1177
                WHERE $course_condition survey_id = '".$survey_id."'";
1178
1179
        // Deleting the survey questions
1180
        Database::query($sql);*/
1181
1182
        // Deleting all the options of the questions of the survey
1183
        //self::delete_all_survey_questions_options($survey_id, $shared);
1184
1185
        // Deleting all the answers on this survey
1186
        //self::delete_all_survey_answers($survey_id);
1187
1188
        return true;
1189
    }
1190
1191
    public static function deleteQuestion($questionId)
1192
    {
1193
        $questionId = (int) $questionId;
1194
        if (empty($questionId)) {
1195
            return false;
1196
        }
1197
1198
        $em = Database::getManager();
1199
        $repo = Container::getSurveyQuestionRepository();
1200
        $question = $repo->find($questionId);
1201
        if ($question) {
1202
            $em->remove($question);
1203
            $em->flush();
1204
1205
            return true;
1206
        }
1207
1208
        return false;
1209
    }
1210
1211
    public static function saveQuestionOptions(CSurvey $survey, CSurveyQuestion $question, $form_content, $dataFromDatabase = [])
1212
    {
1213
        $course_id = api_get_course_int_id();
1214
        $type = $form_content['type'];
1215
1216
        // A percentage question type has options 1 -> 100
1217
        if ('percentage' === $type) {
1218
            for ($i = 1; $i < 101; $i++) {
1219
                $form_content['answers'][] = $i;
1220
            }
1221
        }
1222
        $em = Database::getManager();
1223
1224
        // Table definition
1225
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1226
1227
        // We are editing a question so we first have to remove all the existing options from the database
1228
        $optionsToDelete = [];
1229
        if (isset($dataFromDatabase['answer_data'])) {
1230
            foreach ($dataFromDatabase['answer_data'] as $data) {
1231
                if ('other' === $data['data'] && 'multiplechoiceother' === $type) {
1232
                    continue;
1233
                }
1234
1235
                if (!in_array($data['iid'], $form_content['answersid'])) {
1236
                    $optionsToDelete[] = $data['iid'];
1237
                }
1238
            }
1239
        }
1240
1241
        if (!empty($optionsToDelete)) {
1242
            foreach ($optionsToDelete as $iid) {
1243
                $iid = (int) $iid;
1244
                $sql = "DELETE FROM $table
1245
			            WHERE
1246
			                iid = $iid AND
1247
                            question_id = '".intval($form_content['question_id'])."'
1248
                            ";
1249
                Database::query($sql);
1250
            }
1251
        }
1252
1253
        $counter = 1;
1254
        if (isset($form_content['answers']) && is_array($form_content['answers'])) {
1255
            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...
1256
                $values = isset($form_content['values']) ? (int) $form_content['values'][$i] : 0;
1257
                $answerId = 0;
1258
                if (isset($form_content['answersid']) && isset($form_content['answersid'][$i])) {
1259
                    $answerId = $form_content['answersid'][$i];
1260
                }
1261
                if (empty($answerId)) {
1262
                    $option = new CSurveyQuestionOption();
1263
                    $option
1264
                        ->setQuestion($question)
1265
                        ->setOptionText($form_content['answers'][$i])
1266
                        ->setSurvey($survey)
1267
                        ->setValue($values)
1268
                        ->setSort($counter)
1269
                    ;
1270
                    $em->persist($option);
1271
                    $em->flush();
1272
                    $insertId = $option->getIid();
1273
                    if ($insertId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1274
                        $counter++;
1275
                    }
1276
                } else {
1277
                    $repo = $em->getRepository(CSurveyQuestionOption::class);
1278
                    /** @var CSurveyQuestionOption $option */
1279
                    $option = $repo->find($answerId);
1280
                    if ($option) {
1281
                        $option
1282
                            ->setOptionText($form_content['answers'][$i])
1283
                            ->setValue($values)
1284
                            ->setSort($counter)
1285
                        ;
1286
                        $em->persist($option);
1287
                        $em->flush();
1288
                    }
1289
                    $counter++;
1290
                }
1291
            }
1292
        }
1293
1294
        if ('multiplechoiceother' === $type) {
1295
            if (empty($dataFromDatabase['answer_data'])) {
1296
                $params = [
1297
                    'question_id' => $form_content['question_id'],
1298
                    'survey_id' => $form_content['survey_id'],
1299
                    'option_text' => 'other',
1300
                    'value' => 0,
1301
                    'sort' => $counter,
1302
                ];
1303
                Database::insert($table, $params);
1304
            } else {
1305
                $params = [
1306
                    'option_text' => 'other',
1307
                    'value' => 0,
1308
                    'sort' => $counter,
1309
                ];
1310
                Database::update(
1311
                    $table,
1312
                    $params,
1313
                    [
1314
                        'question_id = ? AND survey_id = ? AND option_text = ?' => [
1315
                            $form_content['question_id'],
1316
                            $form_content['survey_id'],
1317
                            'other',
1318
                        ],
1319
                    ]
1320
                );
1321
            }
1322
        }
1323
    }
1324
1325
    /**
1326
     * This function deletes all the options of the questions of a given survey
1327
     * This function is normally only called when a survey is deleted.
1328
     *
1329
     * @param int $survey_id the id of the survey that has to be deleted
1330
     *
1331
     * @return true
1332
     *
1333
     * @author Patrick Cool <[email protected]>, Ghent University
1334
     *
1335
     * @version January 2007
1336
     */
1337
    public static function delete_all_survey_questions_options($survey_id, $shared = false)
1338
    {
1339
        // Table definitions
1340
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1341
        $course_id = api_get_course_int_id();
1342
        $course_condition = " c_id = $course_id AND ";
1343
        $sql = "DELETE FROM $table_survey_question_option
1344
                WHERE $course_condition survey_id='".intval($survey_id)."'";
1345
1346
        // Deleting the options of the survey questions
1347
        Database::query($sql);
1348
1349
        return true;
1350
    }
1351
1352
    /**
1353
     * SURVEY ANSWERS FUNCTIONS.
1354
     */
1355
1356
    /**
1357
     * This function deletes all the answers anyone has given on this survey
1358
     * This function is normally only called when a survey is deleted.
1359
     *
1360
     * @param $survey_id the id of the survey that has to be deleted
1361
     *
1362
     * @return true
1363
     *
1364
     * @todo write the function
1365
     *
1366
     * @author Patrick Cool <[email protected]>, Ghent University
1367
     *
1368
     * @version January 2007,december 2008
1369
     */
1370
    public static function delete_all_survey_answers($survey_id)
1371
    {
1372
        $course_id = api_get_course_int_id();
1373
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1374
        $survey_id = (int) $survey_id;
1375
        $sql = "DELETE FROM $table
1376
                WHERE c_id = $course_id AND survey_id = $survey_id";
1377
        Database::query($sql);
1378
1379
        return true;
1380
    }
1381
1382
    /**
1383
     * This function gets all the persons who have filled the survey.
1384
     *
1385
     * @param int $survey_id
1386
     *
1387
     * @return array
1388
     *
1389
     * @author Patrick Cool <[email protected]>, Ghent University
1390
     *
1391
     * @version February 2007
1392
     */
1393
    public static function get_people_who_filled_survey(
1394
        $survey_id,
1395
        $all_user_info = false,
1396
        $course_id = null
1397
    ) {
1398
        // Database table definition
1399
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1400
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1401
1402
        // Variable initialisation
1403
        $return = [];
1404
1405
        if (empty($course_id)) {
1406
            $course_id = api_get_course_int_id();
1407
        } else {
1408
            $course_id = (int) $course_id;
1409
        }
1410
1411
        $survey_id = (int) $survey_id;
1412
1413
        if ($all_user_info) {
1414
            $order_clause = api_sort_by_first_name()
1415
                ? ' ORDER BY user.firstname, user.lastname'
1416
                : ' ORDER BY user.lastname, user.firstname';
1417
            $sql = "SELECT DISTINCT
1418
			            answered_user.user as invited_user,
1419
			            user.firstname,
1420
			            user.lastname,
1421
			            user.id as user_id
1422
                    FROM $table_survey_answer answered_user
1423
                    LEFT JOIN $table_user as user
1424
                    ON answered_user.user = user.id
1425
                    WHERE
1426
                        survey_id= '".$survey_id."' ".
1427
                $order_clause;
1428
        } else {
1429
            $sql = "SELECT DISTINCT user FROM $table_survey_answer
1430
			        WHERE survey_id= '".$survey_id."'  ";
1431
1432
            if ('true' === api_get_setting('survey.survey_anonymous_show_answered')) {
1433
                $tblInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
1434
                $tblSurvey = Database::get_course_table(TABLE_SURVEY);
1435
1436
                $sql = "SELECT i.user_id FROM $tblInvitation i
1437
                    INNER JOIN $tblSurvey s
1438
                    ON i.survey_code = s.code
1439
                    WHERE i.answered IS TRUE AND s.iid = $survey_id";
1440
            }
1441
        }
1442
1443
        $res = Database::query($sql);
1444
        while ($row = Database::fetch_assoc($res)) {
1445
            if ($all_user_info) {
1446
                $userInfo = api_get_user_info($row['user_id']);
1447
                $row['user_info'] = $userInfo;
1448
                $return[] = $row;
1449
            } else {
1450
                $return[] = $row['user'];
1451
            }
1452
        }
1453
1454
        return $return;
1455
    }
1456
1457
    /**
1458
     * @return bool
1459
     */
1460
    public static function survey_generation_hash_available()
1461
    {
1462
        if (extension_loaded('mcrypt')) {
1463
            return true;
1464
        }
1465
1466
        return false;
1467
    }
1468
1469
    /**
1470
     * @param int $survey_id
1471
     * @param int $course_id
1472
     * @param int $session_id
1473
     * @param int $group_id
1474
     *
1475
     * @return string
1476
     */
1477
    public static function generate_survey_hash(int $survey_id, int $course_id, int $session_id, int $group_id): string
1478
    {
1479
        $securityKey = api_get_env_variable('kernel.secret');
1480
1481
        return hash(
1482
            'sha512',
1483
            $securityKey.'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id
1484
        );
1485
    }
1486
1487
    /**
1488
     * @param int    $survey_id
1489
     * @param int    $course_id
1490
     * @param int    $session_id
1491
     * @param int    $group_id
1492
     * @param string $hash
1493
     *
1494
     * @return bool
1495
     */
1496
    public static function validate_survey_hash($survey_id, $course_id, $session_id, $group_id, $hash)
1497
    {
1498
        $generatedHash = self::generate_survey_hash($survey_id, $course_id, $session_id, $group_id);
1499
        if ($generatedHash == $hash) {
1500
            return true;
1501
        }
1502
1503
        return false;
1504
    }
1505
1506
    /**
1507
     * @param int $survey_id
1508
     * @param int $course_id
1509
     * @param int $session_id
1510
     * @param int $group_id
1511
     *
1512
     * @return string
1513
     */
1514
    public static function generate_survey_link(
1515
        $survey_id,
1516
        $course_id,
1517
        $session_id,
1518
        $group_id
1519
    ) {
1520
        $code = self::generate_survey_hash(
1521
            $survey_id,
1522
            $course_id,
1523
            $session_id,
1524
            $group_id
1525
        );
1526
1527
        return api_get_path(WEB_CODE_PATH).'survey/link.php?h='.$code.'&i='.$survey_id.'&c='.intval($course_id).'&s='
1528
            .intval($session_id).'&g='.$group_id;
1529
    }
1530
1531
    /**
1532
     * Check if the current user has mandatory surveys no-answered
1533
     * and redirect to fill the first found survey.
1534
     */
1535
    public static function protectByMandatory()
1536
    {
1537
        if (false !== strpos($_SERVER['SCRIPT_NAME'], 'fillsurvey.php')) {
1538
            return;
1539
        }
1540
1541
        $userId = api_get_user_id();
1542
        $courseId = api_get_course_int_id();
1543
        $sessionId = api_get_session_id();
1544
1545
        if (!$userId) {
1546
            return;
1547
        }
1548
1549
        if (!$courseId) {
1550
            return;
1551
        }
1552
1553
        try {
1554
            /** @var CSurveyInvitation $invitation */
1555
            $invitation = Database::getManager()
1556
                ->createQuery("
1557
                    SELECT i FROM ChamiloCourseBundle:CSurveyInvitation i
1558
                    INNER JOIN ChamiloCourseBundle:CSurvey s
1559
                        WITH (s.code = i.surveyCode AND s.cId = i.cId AND s.sessionId = i.sessionId)
1560
                    INNER JOIN ChamiloCoreBundle:ExtraFieldValues efv WITH efv.itemId = s.iid
1561
                    INNER JOIN ChamiloCoreBundle:ExtraField ef WITH efv.field = ef.id
1562
                    WHERE
1563
                        i.answered = 0 AND
1564
                        i.cId = :course AND
1565
                        i.user = :user AND
1566
                        i.sessionId = :session AND
1567
                        :now BETWEEN s.availFrom AND s.availTill AND
1568
                        ef.variable = :variable AND
1569
                        efv.field_value = 1 AND
1570
                        s.surveyType != 3
1571
                    ORDER BY s.availTill ASC
1572
                ")
1573
                ->setMaxResults(1)
1574
                ->setParameters([
1575
                    'course' => $courseId,
1576
                    'user' => $userId,
1577
                    'session' => $sessionId,
1578
                    'now' => new DateTime('UTC', new DateTimeZone('UTC')),
1579
                    'variable' => 'is_mandatory',
1580
                ])
1581
                ->getSingleResult();
1582
        } catch (Exception $e) {
1583
            $invitation = null;
1584
        }
1585
1586
        if (!$invitation) {
1587
            return;
1588
        }
1589
1590
        Display::addFlash(
1591
            Display::return_message(
1592
                get_lang(
1593
                    'A mandatory survey is waiting your answer. To enter the course, you must first complete the survey.'
1594
                ),
1595
                'warning'
1596
            )
1597
        );
1598
1599
        $url = SurveyUtil::generateFillSurveyLink(
1600
            $invitation->getInvitationCode(),
1601
            api_get_course_info(),
1602
            api_get_session_id()
1603
        );
1604
1605
        header('Location: '.$url);
1606
        exit;
1607
    }
1608
1609
    /**
1610
     * This function empty surveys (invitations and answers).
1611
     *
1612
     * @param int $surveyId id of the survey to empty
1613
     *
1614
     * @return bool
1615
     */
1616
    public static function emptySurveyFromId($surveyId)
1617
    {
1618
        // Database table definitions
1619
        $surveyInvitationTable = Database:: get_course_table(TABLE_SURVEY_INVITATION);
1620
        $surveyAnswerTable = Database:: get_course_table(TABLE_SURVEY_ANSWER);
1621
        $surveyTable = Database:: get_course_table(TABLE_SURVEY);
1622
        $surveyId = (int) $surveyId;
1623
        $surveyData = self::get_survey($surveyId);
1624
        if (empty($surveyData)) {
1625
            return false;
1626
        }
1627
1628
        $surveyCode = $surveyData['survey_code'];
1629
        $courseId = (int) $surveyData['c_id'];
1630
        $sessionId = (int) $surveyData['session_id'];
1631
1632
        $sql = "DELETE FROM $surveyInvitationTable
1633
                WHERE session_id = $sessionId AND c_id = $courseId AND survey_code = '$surveyCode' ";
1634
        Database::query($sql);
1635
1636
        $sql = "DELETE FROM $surveyAnswerTable
1637
                WHERE survey_id = $surveyId AND c_id = $courseId ";
1638
        Database::query($sql);
1639
1640
        $sql = "UPDATE $surveyTable
1641
                SET invited = 0, answered = 0
1642
                WHERE iid = $surveyId AND c_id = $courseId AND session_id = $sessionId ";
1643
        Database::query($sql);
1644
1645
        return true;
1646
    }
1647
1648
    /**
1649
     * Copy/duplicate one question (into the same survey).
1650
     * Note: Relies on the question iid to find all necessary info.
1651
     *
1652
     * @param int $questionId
1653
     *
1654
     * @return int The new question's iid, or 0 on error
1655
     */
1656
    public static function copyQuestion($questionId)
1657
    {
1658
        if (empty($questionId)) {
1659
            return 0;
1660
        }
1661
        $questionId = (int) $questionId;
1662
        $questionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
1663
        $optionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1664
1665
        // Get questions
1666
        $sql = "SELECT * FROM $questionTable WHERE iid = $questionId";
1667
        $res = Database::query($sql);
1668
        if (false == $res) {
1669
            // Could not find this question
1670
            return 0;
1671
        }
1672
        $row = Database::fetch_assoc($res);
1673
        $params = [
1674
            //'c_id' => $row['c_id'],
1675
            'survey_id' => $row['survey_id'],
1676
            'survey_question' => trim($row['survey_question']),
1677
            'survey_question_comment' => $row['survey_question_comment'],
1678
            'type' => $row['type'],
1679
            'display' => $row['display'],
1680
            'shared_question_id' => $row['shared_question_id'],
1681
            'max_value' => $row['max_value'],
1682
            'survey_group_pri' => $row['survey_group_pri'],
1683
            'survey_group_sec1' => $row['survey_group_sec1'],
1684
            'survey_group_sec2' => $row['survey_group_sec2'],
1685
        ];
1686
        if (isset($row['is_required'])) {
1687
            $params['is_required'] = $row['is_required'];
1688
        }
1689
        // Get question position
1690
        $sqlSort = "SELECT max(sort) as sort FROM $questionTable
1691
                    WHERE survey_id = ".$row['survey_id'];
1692
        $resSort = Database::query($sqlSort);
1693
        $rowSort = Database::fetch_assoc($resSort);
1694
        $params['sort'] = $rowSort['sort'] + 1;
1695
        // Insert the new question
1696
        $insertId = Database::insert($questionTable, $params);
1697
        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...
1698
            return 0;
1699
        }
1700
1701
        // Get questions options
1702
        $sql = "SELECT * FROM $optionsTable WHERE question_id = $questionId";
1703
        $res = Database::query($sql);
1704
        while ($row = Database::fetch_assoc($res)) {
1705
            $params = [
1706
                //'c_id' => $row['c_id'],
1707
                'question_id' => $insertId,
1708
                'survey_id' => $row['survey_id'],
1709
                'option_text' => $row['option_text'],
1710
                'sort' => $row['sort'],
1711
                'value' => $row['value'],
1712
            ];
1713
            Database::insert($optionsTable, $params);
1714
        }
1715
1716
        return $insertId;
1717
    }
1718
1719
    /**
1720
     * @param array $surveyData
1721
     *
1722
     * @return bool
1723
     */
1724
    public static function removeMultiplicateQuestions(CSurvey $survey, $courseId)
1725
    {
1726
        $surveyId = $survey->getIid();
1727
        $courseId = (int) $courseId;
1728
1729
        if (empty($surveyId) || empty($courseId)) {
1730
            return false;
1731
        }
1732
1733
        $questions = $survey->getQuestions();
1734
        foreach ($questions as $question) {
1735
            // Questions marked with "geneated" were created using the "multiplicate" feature.
1736
            if ('generated' === $question->getSurveyQuestionComment()) {
1737
                self::deleteQuestion($question->getIid());
1738
            }
1739
        }
1740
    }
1741
1742
    /**
1743
     * @return bool
1744
     */
1745
    public static function multiplicateQuestions(CSurvey $survey, $courseId)
1746
    {
1747
        $surveyId = $survey->getIid();
1748
1749
        if (empty($surveyId)) {
1750
            return false;
1751
        }
1752
1753
        $questions = self::get_questions($surveyId);
1754
1755
        if (empty($questions)) {
1756
            return false;
1757
        }
1758
1759
        $extraFieldValue = new ExtraFieldValue('survey');
1760
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
1761
        $groupId = null;
1762
        if ($groupData && !empty($groupData['value'])) {
1763
            $groupId = (int) $groupData['value'];
1764
        }
1765
1766
        if (null === $groupId) {
1767
            $obj = new UserGroupModel();
1768
            $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...
1769
            $classList = $obj->getUserGroupInCourse($options);
1770
1771
            $classToParse = [];
1772
            foreach ($classList as $class) {
1773
                $users = $obj->get_users_by_usergroup($class['id']);
1774
                if (empty($users)) {
1775
                    continue;
1776
                }
1777
                $classToParse[] = [
1778
                    'name' => $class['name'],
1779
                    'users' => $users,
1780
                ];
1781
            }
1782
            self::parseMultiplicateUserList($classToParse, $questions, $courseId, $survey, true);
1783
        } else {
1784
            $groupInfo = GroupManager::get_group_properties($groupId);
1785
            if (!empty($groupInfo)) {
1786
                $users = GroupManager::getStudents($groupInfo['iid'], true);
1787
                if (!empty($users)) {
1788
                    $users = array_column($users, 'id');
1789
                    self::parseMultiplicateUserList(
1790
                        [
1791
                            [
1792
                                'name' => $groupInfo['name'],
1793
                                'users' => $users,
1794
                            ],
1795
                        ],
1796
                        $questions,
1797
                        $courseId,
1798
                        $survey,
1799
                        false
1800
                    );
1801
                }
1802
            }
1803
        }
1804
1805
        return true;
1806
    }
1807
1808
    public static function parseMultiplicateUserList($itemList, $questions, $courseId, CSurvey $survey, $addClassNewPage = false)
1809
    {
1810
        if (empty($itemList) || empty($questions)) {
1811
            return false;
1812
        }
1813
1814
        $surveyId = $survey->getIid();
1815
        $classTag = '{{class_name}}';
1816
        $studentTag = '{{student_full_name}}';
1817
        $classCounter = 0;
1818
1819
        $newQuestionList = [];
1820
        foreach ($questions as $question) {
1821
            $newQuestionList[$question['sort']] = $question;
1822
        }
1823
        ksort($newQuestionList);
1824
1825
        $order = ('true' === api_get_setting('survey.survey_duplicate_order_by_name'));
1826
        foreach ($itemList as $class) {
1827
            $className = $class['name'];
1828
            $users = $class['users'];
1829
            $userInfoList = [];
1830
            foreach ($users as $userId) {
1831
                $userInfoList[] = api_get_user_info($userId);
1832
            }
1833
1834
            if ($order) {
1835
                usort(
1836
                    $userInfoList,
1837
                    function ($a, $b) {
1838
                        return $a['lastname'] > $b['lastname'];
1839
                    }
1840
                );
1841
            }
1842
1843
            foreach ($newQuestionList as $question) {
1844
                $text = $question['question'];
1845
                if (false !== strpos($text, $classTag)) {
1846
                    $replacedText = str_replace($classTag, $className, $text);
1847
                    $values = [
1848
                        'c_id' => $courseId,
1849
                        'question_comment' => 'generated',
1850
                        'type' => $question['type'],
1851
                        'display' => $question['horizontalvertical'],
1852
                        'horizontalvertical' => $question['horizontalvertical'],
1853
                        'question' => $replacedText,
1854
                        'survey_id' => $surveyId,
1855
                        'question_id' => 0,
1856
                        'shared_question_id' => 0,
1857
                        'answers' => $question['answers'] ?? null,
1858
                    ];
1859
                    self::saveQuestion($survey, $values, false);
1860
                    $classCounter++;
1861
                    continue;
1862
                }
1863
1864
                foreach ($userInfoList as $userInfo) {
1865
                    if (false !== strpos($text, $studentTag)) {
1866
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
1867
                        $values = [
1868
                            'c_id' => $courseId,
1869
                            'question_comment' => 'generated',
1870
                            'type' => $question['type'],
1871
                            'display' => $question['horizontalvertical'],
1872
                            'maximum_score' => $question['maximum_score'],
1873
                            'question' => $replacedText,
1874
                            'survey_id' => $surveyId,
1875
                            'question_id' => 0,
1876
                            'shared_question_id' => 0,
1877
                        ];
1878
1879
                        $answers = [];
1880
                        if (!empty($question['answers'])) {
1881
                            foreach ($question['answers'] as $answer) {
1882
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
1883
                                $answers[] = $replacedText;
1884
                            }
1885
                        }
1886
                        $values['answers'] = $answers;
1887
                        self::saveQuestion($survey, $values, false);
1888
                    }
1889
                }
1890
1891
                if ($addClassNewPage && $classCounter < count($itemList)) {
1892
                    // Add end page
1893
                    $values = [
1894
                        'c_id' => $courseId,
1895
                        'question_comment' => 'generated',
1896
                        'type' => 'pagebreak',
1897
                        'display' => 'horizontal',
1898
                        'question' => get_lang('Question for next class'),
1899
                        'survey_id' => $surveyId,
1900
                        'question_id' => 0,
1901
                        'shared_question_id' => 0,
1902
                    ];
1903
                    self::saveQuestion($survey, $values, false);
1904
                }
1905
            }
1906
        }
1907
1908
        return true;
1909
    }
1910
1911
    public static function hasDependency(CSurvey $survey)
1912
    {
1913
        $surveyId = $survey->getIid();
1914
1915
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1916
        $sql = "SELECT COUNT(iid) count FROM $table
1917
                WHERE
1918
                    survey_id = $surveyId AND
1919
                    parent_option_id <> 0
1920
                LIMIT 1
1921
                ";
1922
        $result = Database::query($sql);
1923
        $row = Database::fetch_array($result);
1924
1925
        if ($row) {
1926
            return $row['count'] > 0;
1927
        }
1928
1929
        return false;
1930
    }
1931
1932
    /**
1933
     * @return int
1934
     */
1935
    public static function getCountPages(CSurvey $survey)
1936
    {
1937
        $surveyId = $survey->getIid();
1938
1939
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1940
1941
        // pagebreak
1942
        $sql = "SELECT COUNT(iid) FROM $table
1943
                WHERE
1944
                    survey_question NOT LIKE '%{{%' AND
1945
                    type = 'pagebreak' AND
1946
                    survey_id = $surveyId";
1947
        $result = Database::query($sql);
1948
        $numberPageBreaks = Database::result($result, 0, 0);
1949
1950
        // No pagebreak
1951
        $sql = "SELECT COUNT(iid) FROM $table
1952
                WHERE
1953
                    survey_question NOT LIKE '%{{%' AND
1954
                    type != 'pagebreak' AND
1955
                    survey_id = $surveyId";
1956
        $result = Database::query($sql);
1957
        $countOfQuestions = Database::result($result, 0, 0);
1958
1959
        if (1 == $survey->getOneQuestionPerPage()) {
1960
            if (!empty($countOfQuestions)) {
1961
                return $countOfQuestions;
1962
            }
1963
1964
            return 1;
1965
        }
1966
1967
        if (empty($numberPageBreaks)) {
1968
            return 1;
1969
        }
1970
1971
        return $numberPageBreaks + 1;
1972
    }
1973
1974
    /**
1975
     * Check whether this survey has ended. If so, display message and exit this script.
1976
     */
1977
    public static function checkTimeAvailability(?CSurvey $survey): void
1978
    {
1979
        if (null === $survey) {
1980
            api_not_allowed(true);
1981
        }
1982
1983
        $utcZone = new DateTimeZone('UTC');
1984
        $startDate = $survey->getAvailFrom();
1985
        $endDate = $survey->getAvailTill();
1986
        $currentDate = new DateTime('now', $utcZone);
1987
        $currentDate->modify('today');
1988
1989
        $returnMessage = false;
1990
        if ($currentDate < $startDate) {
1991
            $returnMessage =  Display:: return_message(
1992
                get_lang('This survey is not yet available. Please try again later. Thank you.'),
1993
                'warning',
1994
                false
1995
            );
1996
        }
1997
1998
        if ($currentDate > $endDate) {
1999
            $returnMessage = Display:: return_message(
2000
                get_lang('Sorry, this survey is not available anymore. Thank you for trying.'),
2001
                'warning',
2002
                false
2003
            );
2004
        }
2005
2006
        if (false !== $returnMessage) {
2007
            $content = Display::page_header($survey->getTitle());
2008
            $content .= $returnMessage;
2009
            $template = new Template();
2010
            $template->assign('actions', Display::toolbarAction('toolbar', []));
2011
            $template->assign('content', $content);
2012
            $template->display_one_col_template();
2013
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
2014
        }
2015
    }
2016
2017
    public static function getUserInvitationsForSurveyInCourse(
2018
        int    $userId,
2019
        string $surveyCode,
2020
        int    $courseId,
2021
        int    $sessionId = 0,
2022
        int    $groupId = 0,
2023
        int    $lpItemId = 0
2024
    ): array {
2025
2026
        $em = Database::getManager();
2027
        $invitationRepo = $em->getRepository(CSurveyInvitation::class);
2028
        $surveyRepo = $em->getRepository(CSurvey::class);
2029
        $survey = $surveyRepo->findBy(['code' => $surveyCode]);
2030
2031
        $criteria = [
2032
            'user' => api_get_user_entity($userId),
2033
            'course' => api_get_course_entity($courseId),
2034
            'session' => api_get_session_entity($sessionId),
2035
            'group' => api_get_group_entity($groupId),
2036
            'survey' => $survey,
2037
        ];
2038
2039
        if (is_int($lpItemId) && $lpItemId > 0) {
2040
            $criteria['lpItemId'] = $lpItemId;
2041
        }
2042
2043
        return $invitationRepo->findBy(
2044
            $criteria,
2045
            ['invitationDate' => 'DESC']
2046
        );
2047
    }
2048
2049
2050
    /**
2051
     * @param array $userInfo
2052
     * @param int   $answered (1 = answered 0 = not answered)
2053
     *
2054
     * @return string
2055
     */
2056
    public static function surveyReport($userInfo, $answered = 0)
2057
    {
2058
        $userId = isset($userInfo['user_id']) ? (int) $userInfo['user_id'] : 0;
2059
        $answered = (int) $answered;
2060
2061
        if (empty($userId)) {
2062
            return '';
2063
        }
2064
2065
        $em = Database::getManager();
2066
        $repo = $em->getRepository(CSurveyInvitation::class);
2067
        $repoSurvey = $em->getRepository(CSurvey::class);
2068
        $invitations = $repo->findBy(['user' => $userId, 'answered' => $answered]);
2069
        $mainUrl = api_get_path(WEB_CODE_PATH).'survey/survey.php?';
2070
        $content = '';
2071
2072
        if (empty($answered)) {
2073
            $content .= Display::page_subheader(get_lang('Unanswered'));
2074
        } else {
2075
            $content .= Display::page_subheader(get_lang('Answered'));
2076
        }
2077
2078
        if (!empty($invitations)) {
2079
            $table = new HTML_Table(['class' => 'table']);
2080
            $table->setHeaderContents(0, 0, get_lang('Survey name'));
2081
            $table->setHeaderContents(0, 1, get_lang('Course'));
2082
2083
            if (empty($answered)) {
2084
                $table->setHeaderContents(0, 2, get_lang('Survey').' - '.get_lang('End Date'));
2085
            }
2086
2087
            // Not answered
2088
            /** @var CSurveyInvitation $invitation */
2089
            $row = 1;
2090
            foreach ($invitations as $invitation) {
2091
                $course = $invitation->getCourse();
2092
                $courseId = $course->getId();
2093
                $courseCode = $course->getCode();
2094
                $sessionId = $invitation->getSession() ? $invitation->getSession()->getId() : 0;
2095
2096
                if (!empty($answered)) {
2097
                    // check if user is subscribed to the course/session
2098
                    if (empty($sessionId)) {
2099
                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode);
2100
                    } else {
2101
                        $subscribe = CourseManager::is_user_subscribed_in_course(
2102
                            $userId,
2103
                            $courseCode,
2104
                            true,
2105
                            $sessionId
2106
                        );
2107
                    }
2108
2109
                    // User is not subscribe skip!
2110
                    if (empty($subscribe)) {
2111
                        continue;
2112
                    }
2113
                }
2114
2115
                $survey = $invitation->getSurvey();
2116
                if (null === $survey) {
2117
                    continue;
2118
                }
2119
2120
                $url = $mainUrl.'survey_id='.$survey->getIid().'&cid='.$courseId.'&sid='.$sessionId;
2121
                $title = $survey->getTitle();
2122
                $title = Display::url($title, $url);
2123
                $courseTitle = $course->getTitle();
2124
                if (!empty($sessionId)) {
2125
                    $courseTitle .= ' ('.$invitation->getSession()->getTitle().')';
2126
                }
2127
2128
                $surveyData = self::get_survey($survey->getIid(), 0, $courseCode);
2129
                $table->setCellContents($row, 0, $title);
2130
                $table->setCellContents($row, 1, $courseTitle);
2131
2132
                if (empty($answered)) {
2133
                    $table->setHeaderContents(
2134
                        $row,
2135
                        2,
2136
                        api_get_local_time(
2137
                            $survey->getAvailTill(),
2138
                            null,
2139
                            null,
2140
                            true,
2141
                            false
2142
                        )
2143
                    );
2144
                }
2145
2146
                if (!empty($answered) && 0 == $survey->getAnonymous()) {
2147
                    $answers = SurveyUtil::displayCompleteReport(
2148
                        $surveyData,
2149
                        $userId,
2150
                        false,
2151
                        false,
2152
                        false
2153
                    );
2154
                    $table->setCellContents(++$row, 0, $answers);
2155
                    $table->setCellContents(++$row, 1, '');
2156
                }
2157
2158
                $row++;
2159
            }
2160
            $content .= $table->toHtml();
2161
        } else {
2162
            $content .= Display::return_message(get_lang('No data available'));
2163
        }
2164
2165
        return $content;
2166
    }
2167
2168
    public static function sendToTutors(CSurvey $survey)
2169
    {
2170
        $surveyId = $survey->getIid();
2171
2172
        $extraFieldValue = new ExtraFieldValue('survey');
2173
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
2174
        if ($groupData && !empty($groupData['value'])) {
2175
            $groupInfo = GroupManager::get_group_properties($groupData['value']);
2176
            if ($groupInfo) {
2177
                $tutors = GroupManager::getTutors($groupInfo);
2178
                if (!empty($tutors)) {
2179
                    SurveyUtil::saveInviteMail(
2180
                        $survey,
2181
                        ' ',
2182
                        ' ',
2183
                        false
2184
                    );
2185
2186
                    foreach ($tutors as $tutor) {
2187
                        $subject = sprintf(get_lang('GroupSurveyX'), $groupInfo['name']);
2188
                        $content = sprintf(
2189
                            get_lang('HelloXGroupX'),
2190
                            $tutor['complete_name'],
2191
                            $groupInfo['name']
2192
                        );
2193
2194
                        SurveyUtil::saveInvitations(
2195
                            $survey,
2196
                            ['users' => $tutor['user_id']],
2197
                            $subject,
2198
                            $content,
2199
                            false,
2200
                            true,
2201
                            false,
2202
                            true
2203
                        );
2204
                    }
2205
                    Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false));
2206
                }
2207
                SurveyUtil::updateInvitedCount($survey);
2208
2209
                return true;
2210
            }
2211
        }
2212
2213
        return false;
2214
    }
2215
2216
    public static function getInvitationsAnswered(
2217
        $surveyCode,
2218
        $courseId,
2219
        $sessionId = 0
2220
    ): array
2221
    {
2222
        $invitationRepo = Database::getManager()->getRepository(CSurveyInvitation::class);
2223
2224
        return $invitationRepo->findBy(
2225
            [
2226
                'cId' => $courseId,
2227
                'sessionId' => $sessionId,
2228
                'answered' => true,
2229
                'surveyCode' => $surveyCode,
2230
            ],
2231
            ['invitationDate' => 'DESC']
2232
        );
2233
    }
2234
}
2235