SurveyManager::emptySurveyFromId()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 20
nc 2
nop 1
dl 0
loc 30
rs 9.6
c 0
b 0
f 0
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 successfully'),
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 successfully'),
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  = (int) $survey->getIid();
747
        $courseId  = (int) 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 = $lpItemId ? ' AND c_lp_item_id = '.(int) $lpItemId : '';
755
756
        $sessionWhere = $sessionId > 0
757
            ? 'session_id = '.$sessionId
758
            : '(session_id IS NULL OR session_id = 0)';
759
760
        $courseWhere = $courseId > 0 ? ' AND c_id = '.$courseId : '';
761
762
        $userId = is_numeric($user) ? (int) $user : (int) api_get_user_id();
763
764
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
765
        $sql = "UPDATE $table
766
            SET answered_at = '".api_get_utc_datetime()."', answered = 1
767
            WHERE $sessionWhere
768
              AND user_id = $userId
769
              AND survey_id = $surveyId
770
              $courseWhere
771
              $lpItemCondition";
772
        Database::query($sql);
773
    }
774
775
    /**
776
     * This function return the "icon" of the question type.
777
     *
778
     * @param string $type
779
     *
780
     * @author Patrick Cool <[email protected]>, Ghent University
781
     *
782
     * @version February 2007
783
     */
784
    public static function icon_question($type)
785
    {
786
        // the possible question types
787
        $possible_types = [
788
            'personality',
789
            'yesno',
790
            'multiplechoice',
791
            'multipleresponse',
792
            'open',
793
            'dropdown',
794
            'comment',
795
            'pagebreak',
796
            'percentage',
797
            'score',
798
        ];
799
800
        // the images array
801
        $icon_question = [
802
            'yesno' => 'thumbs-up-down',
803
            'personality' => 'thumbs-up-down',
804
            'multiplechoice' => 'format-list-bulleted',
805
            'multipleresponse' => 'format-list-bulleted-square',
806
            'open' => 'form-textarea',
807
            'dropdown' => 'form-dropdown',
808
            'percentage' => 'percent-box-outline',
809
            'score' => 'format-annotation-plus',
810
            'comment' => 'format-align-top',
811
            'pagebreak' => 'format-page-break',
812
        ];
813
814
        if (in_array($type, $possible_types)) {
815
            return $icon_question[$type];
816
        }
817
818
        return false;
819
    }
820
821
    /**
822
     * This function retrieves all the information of a question.
823
     *
824
     * @param int  $question_id the id of the question
825
     * @param bool $shared
826
     *
827
     * @return array
828
     *
829
     * @author Patrick Cool <[email protected]>, Ghent University
830
     *
831
     * @version January 2007
832
     *
833
     * @todo one sql call should do the trick
834
     */
835
    public static function get_question($question_id)
836
    {
837
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
838
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
839
        $course_id = api_get_course_int_id();
840
        $question_id = (int) $question_id;
841
842
        if (empty($question_id)) {
843
            return [];
844
        }
845
846
        $sql = "SELECT * FROM $tbl_survey_question
847
                WHERE iid = $question_id
848
                ORDER BY `sort` ";
849
850
        $sqlOption = "  SELECT * FROM $table_survey_question_option
851
                        WHERE question_id='".$question_id."'
852
                        ORDER BY `sort` ";
853
        // Getting the information of the question
854
        $result = Database::query($sql);
855
        $row = Database::fetch_assoc($result);
856
857
        $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...
858
        $return['parent_id'] = isset($row['parent_id']) ? $row['parent_id'] : 0;
859
        $return['parent_option_id'] = isset($row['parent_option_id']) ? $row['parent_option_id'] : 0;
860
        $return['question_id'] = $row['iid'];
861
        $return['type'] = $row['type'];
862
        $return['question'] = $row['survey_question'];
863
        $return['horizontalvertical'] = $row['display'];
864
        $return['shared_question_id'] = $row['shared_question_id'];
865
        $return['maximum_score'] = $row['max_value'];
866
        $return['is_required'] = $row['is_required'];
867
868
        if (0 != $row['survey_group_pri']) {
869
            $return['assigned'] = $row['survey_group_pri'];
870
            $return['choose'] = 1;
871
        } else {
872
            $return['assigned1'] = $row['survey_group_sec1'];
873
            $return['assigned2'] = $row['survey_group_sec2'];
874
            $return['choose'] = 2;
875
        }
876
877
        // Getting the information of the question options
878
        $result = Database::query($sqlOption);
879
        $counter = 0;
880
        while ($row = Database::fetch_assoc($result)) {
881
            /** @todo this should be renamed to options instead of answers */
882
            $return['answers'][] = $row['option_text'];
883
            $return['values'][] = $row['value'];
884
            $return['answer_data'][$counter]['data'] = $row['option_text'];
885
            $return['answer_data'][$counter]['iid'] = $row['iid'];
886
            /** @todo this can be done more elegantly (used in reporting) */
887
            $return['answersid'][] = $row['iid'];
888
            $counter++;
889
        }
890
891
        return $return;
892
    }
893
894
    /**
895
     * This function gets all the question of any given survey.
896
     *
897
     * @param int $surveyId the id of the survey
898
     * @param int $courseId
899
     *
900
     * @return array containing all the questions of the survey
901
     *
902
     * @author Patrick Cool <[email protected]>, Ghent University
903
     *
904
     * @version February 2007
905
     *
906
     * @todo one sql call should do the trick
907
     */
908
    public static function get_questions($surveyId, $courseId = 0)
909
    {
910
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
911
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
912
913
        $courseId = (int) $courseId;
914
        $surveyId = (int) $surveyId;
915
916
        // Getting the information of the question
917
        $sql = "SELECT * FROM $tbl_survey_question
918
		        WHERE survey_id= $surveyId ";
919
        $result = Database::query($sql);
920
        $questions = [];
921
        while ($row = Database::fetch_assoc($result)) {
922
            $questionId = $row['iid'];
923
            $questions[$questionId]['survey_id'] = $surveyId;
924
            $questions[$questionId]['question_id'] = $questionId;
925
            $questions[$questionId]['type'] = $row['type'];
926
            $questions[$questionId]['question'] = $row['survey_question'];
927
            $questions[$questionId]['horizontalvertical'] = $row['display'];
928
            $questions[$questionId]['maximum_score'] = $row['max_value'];
929
            $questions[$questionId]['sort'] = $row['sort'];
930
            $questions[$questionId]['survey_question_comment'] = $row['survey_question_comment'];
931
932
            // Getting the information of the question options
933
            $sql = "SELECT * FROM $table_survey_question_option
934
		             WHERE survey_id= $surveyId  AND question_id = $questionId";
935
            $resultOptions = Database::query($sql);
936
            while ($rowOption = Database::fetch_assoc($resultOptions)) {
937
                $questions[$questionId]['answers'][] = $rowOption['option_text'];
938
            }
939
        }
940
941
        return $questions;
942
    }
943
944
    public static function saveQuestion(CSurvey $survey, array $form_content, bool $showMessage = true, array $dataFromDatabase = [])
945
    {
946
        $surveyId = $survey->getIid();
947
948
        $error = false;
949
        $message = '';
950
        if (strlen($form_content['question']) > 1) {
951
            // Checks length of the question
952
            $empty_answer = false;
953
            if (1 == $survey->getSurveyType()) {
954
                if (empty($form_content['choose'])) {
955
                    return 'PleaseChooseACondition';
956
                }
957
958
                if ((2 == $form_content['choose']) &&
959
                    ($form_content['assigned1'] == $form_content['assigned2'])
960
                ) {
961
                    return 'ChooseDifferentCategories';
962
                }
963
            }
964
965
            if ('percentage' !== $form_content['type']) {
966
                if (isset($form_content['answers'])) {
967
                    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...
968
                        if (strlen($form_content['answers'][$i]) < 1) {
969
                            $empty_answer = true;
970
                            break;
971
                        }
972
                    }
973
                }
974
            }
975
976
            if ('score' === $form_content['type']) {
977
                if (strlen($form_content['maximum_score']) < 1) {
978
                    $empty_answer = true;
979
                }
980
            }
981
982
            $em = Database::getManager();
983
            $course_id = api_get_course_int_id();
984
            if (!$empty_answer) {
985
                // Table definitions
986
                $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
987
988
                // Getting all the information of the survey
989
                $survey_data = self::get_survey($surveyId);
990
991
                // Storing a new question
992
                if (empty($form_content['question_id']) || !is_numeric($form_content['question_id'])) {
993
                    // Finding the max sort order of the questions in the given survey
994
                    $sql = "SELECT max(sort) AS max_sort
995
					        FROM $tbl_survey_question
996
                            WHERE survey_id = $surveyId ";
997
                    $result = Database::query($sql);
998
                    $row = Database::fetch_assoc($result);
999
                    $max_sort = $row['max_sort'];
1000
1001
                    $question = new CSurveyQuestion();
1002
1003
                    // Some variables defined for survey-test type
1004
                    if (isset($_POST['choose'])) {
1005
                        if (1 == $_POST['choose']) {
1006
                            $question->setSurveyGroupPri($_POST['assigned']);
1007
                        } elseif (2 == $_POST['choose']) {
1008
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1009
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1010
                        }
1011
                    }
1012
1013
                    $question
1014
                        ->setSurveyQuestionComment($form_content['question_comment'] ?? '')
1015
                        ->setMaxValue($form_content['maximum_score'] ?? 0)
1016
                        ->setDisplay($form_content['horizontalvertical'] ?? '')
1017
                        //->setCId($course_id)
1018
                        ->setSurvey($survey)
1019
                        ->setSurveyQuestion($form_content['question'])
1020
                        ->setType($form_content['type'])
1021
                        ->setSort($max_sort + 1)
1022
                        ->setSharedQuestionId((int) $form_content['shared_question_id'])
1023
                    ;
1024
1025
                    $question->setIsMandatory(isset($form_content['is_required']));
1026
1027
                    $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...
1028
                    $params['parent_option_id'] = 0;
1029
                    if (isset($form_content['parent_id']) &&
1030
                        isset($form_content['parent_option_id']) &&
1031
                        !empty($form_content['parent_id']) &&
1032
                        !empty($form_content['parent_option_id'])
1033
                    ) {
1034
                        $params['parent_id'] = $form_content['parent_id'];
1035
                        $params['parent_option_id'] = $form_content['parent_option_id'];
1036
                    }
1037
1038
                    $em->persist($question);
1039
                    $em->flush();
1040
1041
                    $question_id = $question->getIid();
1042
                    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...
1043
                        /*$sql = "UPDATE $tbl_survey_question SET question_id = $question_id
1044
                                WHERE iid = $question_id";
1045
                        Database::query($sql);*/
1046
                        $form_content['question_id'] = $question_id;
1047
                        $message = 'The question has been added.';
1048
                        $error = false;
1049
                    }
1050
                } else {
1051
                    $repo = $em->getRepository(CSurveyQuestion::class);
1052
                    $repoOption = $em->getRepository(CSurveyQuestionOption::class);
1053
                    /** @var CSurveyQuestion $question */
1054
                    $question = $repo->find($form_content['question_id']);
1055
1056
                    if (isset($_POST['choose'])) {
1057
                        if (1 == $_POST['choose']) {
1058
                            $question->setSurveyGroupPri($_POST['assigned']);
1059
                            $question->setSurveyGroupSec1(0);
1060
                            $question->setSurveyGroupSec2(0);
1061
                        } elseif (2 == $_POST['choose']) {
1062
                            $question->setSurveyGroupPri(0);
1063
                            $question->setSurveyGroupSec1($_POST['assigned1']);
1064
                            $question->setSurveyGroupSec2($_POST['assigned2']);
1065
                        }
1066
                    }
1067
1068
                    $maxScore = isset($form_content['maximum_score']) ? (int) $form_content['maximum_score'] : 0;
1069
                    $questionComment = $form_content['question_comment'] ?? '';
1070
                    $question
1071
                        ->setSurveyQuestionComment($questionComment)
1072
                        ->setSurveyQuestion($form_content['question'])
1073
                        ->setDisplay($form_content['horizontalvertical'])
1074
                        ->setMaxValue($maxScore)
1075
                    ;
1076
1077
                    $question->isMandatory(isset($form_content['is_required']));
1078
                    $params['parent_id'] = 0;
1079
                    $params['parent_option_id'] = 0;
1080
                    if (isset($form_content['parent_id']) &&
1081
                        isset($form_content['parent_option_id']) &&
1082
                        !empty($form_content['parent_id']) &&
1083
                        !empty($form_content['parent_option_id'])
1084
                    ) {
1085
                        $question->setParent($repo->find($form_content['parent_id']));
1086
                        $question->setParentOption($repoOption->find($form_content['parent_option_id']));
1087
                    }
1088
1089
                    $em->persist($question);
1090
                    $em->flush();
1091
                    $message = 'QuestionUpdated';
1092
                    $error = false;
1093
                }
1094
                // Storing the options of the question
1095
                self::saveQuestionOptions($survey, $question, $form_content, $dataFromDatabase);
1096
            } else {
1097
                $message = 'PleasFillAllAnswer';
1098
                $error = true;
1099
            }
1100
        } else {
1101
            $message = 'PleaseEnterAQuestion';
1102
            $error = true;
1103
        }
1104
1105
        if ($showMessage) {
1106
            if (!empty($message)) {
1107
                Display::addFlash(Display::return_message(get_lang($message)));
1108
            }
1109
        }
1110
        $result = [
1111
            'error' => $error,
1112
            'message' => $message,
1113
        ];
1114
1115
        return $result;
1116
    }
1117
1118
    /**
1119
     * Moves a survey question within the ordered list.
1120
     *
1121
     * @param string $direction The direction to move the question ('moveup' or 'movedown').
1122
     * @param int    $surveyQuestionId The ID of the survey question to move.
1123
     * @param int    $surveyId The ID of the survey to which the question belongs.
1124
     */
1125
    public static function moveSurveyQuestion(string $direction, int $surveyQuestionId, int $surveyId): void
1126
    {
1127
        $em = Database::getManager();
1128
        $repo = $em->getRepository(CSurveyQuestion::class);
1129
        $sortDirection = $direction === 'moveup' ? 'DESC' : 'ASC';
1130
        $questions = $repo->findBy(['survey' => $surveyId], ['sort' => $sortDirection]);
1131
1132
        $found = false;
1133
        foreach ($questions as $question) {
1134
            if ($found) {
1135
                $secondQuestion = $question;
1136
                $found = false;
1137
                break;
1138
            }
1139
            if ($question->getIid() == $surveyQuestionId) {
1140
                $found = true;
1141
                $firstQuestion = $question;
1142
            }
1143
        }
1144
1145
        if (isset($firstQuestion) && isset($secondQuestion)) {
1146
            $tempSort = $firstQuestion->getSort();
1147
            $firstQuestion->setSort($secondQuestion->getSort());
1148
            $secondQuestion->setSort($tempSort);
1149
1150
            $em->persist($firstQuestion);
1151
            $em->persist($secondQuestion);
1152
            $em->flush();
1153
        }
1154
    }
1155
1156
    /**
1157
     * This function deletes all the questions of a given survey
1158
     * This function is normally only called when a survey is deleted.
1159
     *
1160
     * @param int $survey_id the id of the survey that has to be deleted
1161
     *
1162
     * @return bool
1163
     *
1164
     * @author Patrick Cool <[email protected]>, Ghent University
1165
     *
1166
     * @version January 2007
1167
     */
1168
    public static function delete_all_survey_questions($survey_id, $shared = false)
1169
    {
1170
        $course_id = api_get_course_int_id();
1171
        $survey_id = (int) $survey_id;
1172
1173
        /*$sql = "DELETE FROM $table_survey_question
1174
                WHERE $course_condition survey_id = '".$survey_id."'";
1175
1176
        // Deleting the survey questions
1177
        Database::query($sql);*/
1178
1179
        // Deleting all the options of the questions of the survey
1180
        //self::delete_all_survey_questions_options($survey_id, $shared);
1181
1182
        // Deleting all the answers on this survey
1183
        //self::delete_all_survey_answers($survey_id);
1184
1185
        return true;
1186
    }
1187
1188
    public static function deleteQuestion($questionId)
1189
    {
1190
        $questionId = (int) $questionId;
1191
        if (empty($questionId)) {
1192
            return false;
1193
        }
1194
1195
        $em = Database::getManager();
1196
        $repo = Container::getSurveyQuestionRepository();
1197
        $question = $repo->find($questionId);
1198
        if ($question) {
1199
            $em->remove($question);
1200
            $em->flush();
1201
1202
            return true;
1203
        }
1204
1205
        return false;
1206
    }
1207
1208
    public static function saveQuestionOptions(CSurvey $survey, CSurveyQuestion $question, $form_content, $dataFromDatabase = [])
1209
    {
1210
        $course_id = api_get_course_int_id();
1211
        $type = $form_content['type'];
1212
1213
        // A percentage question type has options 1 -> 100
1214
        if ('percentage' === $type) {
1215
            for ($i = 1; $i < 101; $i++) {
1216
                $form_content['answers'][] = $i;
1217
            }
1218
        }
1219
        $em = Database::getManager();
1220
1221
        // Table definition
1222
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1223
1224
        // We are editing a question so we first have to remove all the existing options from the database
1225
        $optionsToDelete = [];
1226
        if (isset($dataFromDatabase['answer_data'])) {
1227
            foreach ($dataFromDatabase['answer_data'] as $data) {
1228
                if ('other' === $data['data'] && 'multiplechoiceother' === $type) {
1229
                    continue;
1230
                }
1231
1232
                if (!in_array($data['iid'], $form_content['answersid'])) {
1233
                    $optionsToDelete[] = $data['iid'];
1234
                }
1235
            }
1236
        }
1237
1238
        if (!empty($optionsToDelete)) {
1239
            foreach ($optionsToDelete as $iid) {
1240
                $iid = (int) $iid;
1241
                $sql = "DELETE FROM $table
1242
			            WHERE
1243
			                iid = $iid AND
1244
                            question_id = '".intval($form_content['question_id'])."'
1245
                            ";
1246
                Database::query($sql);
1247
            }
1248
        }
1249
1250
        $counter = 1;
1251
        if (isset($form_content['answers']) && is_array($form_content['answers'])) {
1252
            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...
1253
                $values = isset($form_content['values']) ? (int) $form_content['values'][$i] : 0;
1254
                $answerId = 0;
1255
                if (isset($form_content['answersid']) && isset($form_content['answersid'][$i])) {
1256
                    $answerId = $form_content['answersid'][$i];
1257
                }
1258
                if (empty($answerId)) {
1259
                    $option = new CSurveyQuestionOption();
1260
                    $option
1261
                        ->setQuestion($question)
1262
                        ->setOptionText($form_content['answers'][$i])
1263
                        ->setSurvey($survey)
1264
                        ->setValue($values)
1265
                        ->setSort($counter)
1266
                    ;
1267
                    $em->persist($option);
1268
                    $em->flush();
1269
                    $insertId = $option->getIid();
1270
                    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...
1271
                        $counter++;
1272
                    }
1273
                } else {
1274
                    $repo = $em->getRepository(CSurveyQuestionOption::class);
1275
                    /** @var CSurveyQuestionOption $option */
1276
                    $option = $repo->find($answerId);
1277
                    if ($option) {
1278
                        $option
1279
                            ->setOptionText($form_content['answers'][$i])
1280
                            ->setValue($values)
1281
                            ->setSort($counter)
1282
                        ;
1283
                        $em->persist($option);
1284
                        $em->flush();
1285
                    }
1286
                    $counter++;
1287
                }
1288
            }
1289
        }
1290
1291
        if ('multiplechoiceother' === $type) {
1292
            if (empty($dataFromDatabase['answer_data'])) {
1293
                $params = [
1294
                    'question_id' => $form_content['question_id'],
1295
                    'survey_id' => $form_content['survey_id'],
1296
                    'option_text' => 'other',
1297
                    'value' => 0,
1298
                    'sort' => $counter,
1299
                ];
1300
                Database::insert($table, $params);
1301
            } else {
1302
                $params = [
1303
                    'option_text' => 'other',
1304
                    'value' => 0,
1305
                    'sort' => $counter,
1306
                ];
1307
                Database::update(
1308
                    $table,
1309
                    $params,
1310
                    [
1311
                        'question_id = ? AND survey_id = ? AND option_text = ?' => [
1312
                            $form_content['question_id'],
1313
                            $form_content['survey_id'],
1314
                            'other',
1315
                        ],
1316
                    ]
1317
                );
1318
            }
1319
        }
1320
    }
1321
1322
    /**
1323
     * This function deletes all the options of the questions of a given survey
1324
     * This function is normally only called when a survey is deleted.
1325
     *
1326
     * @param int $survey_id the id of the survey that has to be deleted
1327
     *
1328
     * @return true
1329
     *
1330
     * @author Patrick Cool <[email protected]>, Ghent University
1331
     *
1332
     * @version January 2007
1333
     */
1334
    public static function delete_all_survey_questions_options($survey_id, $shared = false)
1335
    {
1336
        // Table definitions
1337
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1338
        $course_id = api_get_course_int_id();
1339
        $course_condition = " c_id = $course_id AND ";
1340
        $sql = "DELETE FROM $table_survey_question_option
1341
                WHERE $course_condition survey_id='".intval($survey_id)."'";
1342
1343
        // Deleting the options of the survey questions
1344
        Database::query($sql);
1345
1346
        return true;
1347
    }
1348
1349
    /**
1350
     * SURVEY ANSWERS FUNCTIONS.
1351
     */
1352
1353
    /**
1354
     * This function deletes all the answers anyone has given on this survey
1355
     * This function is normally only called when a survey is deleted.
1356
     *
1357
     * @param $survey_id the id of the survey that has to be deleted
1358
     *
1359
     * @return true
1360
     *
1361
     * @todo write the function
1362
     *
1363
     * @author Patrick Cool <[email protected]>, Ghent University
1364
     *
1365
     * @version January 2007,december 2008
1366
     */
1367
    public static function delete_all_survey_answers($survey_id)
1368
    {
1369
        $course_id = api_get_course_int_id();
1370
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1371
        $survey_id = (int) $survey_id;
1372
        $sql = "DELETE FROM $table
1373
                WHERE c_id = $course_id AND survey_id = $survey_id";
1374
        Database::query($sql);
1375
1376
        return true;
1377
    }
1378
1379
    /**
1380
     * This function gets all the persons who have filled the survey.
1381
     *
1382
     * @param int $survey_id
1383
     *
1384
     * @return array
1385
     *
1386
     * @author Patrick Cool <[email protected]>, Ghent University
1387
     *
1388
     * @version February 2007
1389
     */
1390
    public static function get_people_who_filled_survey(
1391
        $survey_id,
1392
        $all_user_info = false,
1393
        $course_id = null
1394
    ) {
1395
        // Database table definition
1396
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1397
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1398
1399
        // Variable initialisation
1400
        $return = [];
1401
1402
        if (empty($course_id)) {
1403
            $course_id = api_get_course_int_id();
1404
        } else {
1405
            $course_id = (int) $course_id;
1406
        }
1407
1408
        $survey_id = (int) $survey_id;
1409
1410
        if ($all_user_info) {
1411
            $order_clause = api_sort_by_first_name()
1412
                ? ' ORDER BY user.firstname, user.lastname'
1413
                : ' ORDER BY user.lastname, user.firstname';
1414
            $sql = "SELECT DISTINCT
1415
			            answered_user.user as invited_user,
1416
			            user.firstname,
1417
			            user.lastname,
1418
			            user.id as user_id
1419
                    FROM $table_survey_answer answered_user
1420
                    LEFT JOIN $table_user as user
1421
                    ON answered_user.user = user.id
1422
                    WHERE
1423
                        survey_id= '".$survey_id."' ".
1424
                $order_clause;
1425
        } else {
1426
            $sql = "SELECT DISTINCT user FROM $table_survey_answer
1427
			        WHERE survey_id= '".$survey_id."'  ";
1428
1429
            if ('true' === api_get_setting('survey.survey_anonymous_show_answered')) {
1430
                $tblInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
1431
                $tblSurvey = Database::get_course_table(TABLE_SURVEY);
1432
1433
                $sql = "SELECT i.user_id FROM $tblInvitation i
1434
                    INNER JOIN $tblSurvey s
1435
                    ON i.survey_code = s.code
1436
                    WHERE i.answered IS TRUE AND s.iid = $survey_id";
1437
            }
1438
        }
1439
1440
        $res = Database::query($sql);
1441
        while ($row = Database::fetch_assoc($res)) {
1442
            if ($all_user_info) {
1443
                $userInfo = api_get_user_info($row['user_id']);
1444
                $row['user_info'] = $userInfo;
1445
                $return[] = $row;
1446
            } else {
1447
                $return[] = $row['user'];
1448
            }
1449
        }
1450
1451
        return $return;
1452
    }
1453
1454
    /**
1455
     * @return bool
1456
     */
1457
    public static function survey_generation_hash_available()
1458
    {
1459
        if (extension_loaded('mcrypt')) {
1460
            return true;
1461
        }
1462
1463
        return false;
1464
    }
1465
1466
    /**
1467
     * @param int $survey_id
1468
     * @param int $course_id
1469
     * @param int $session_id
1470
     * @param int $group_id
1471
     *
1472
     * @return string
1473
     */
1474
    public static function generate_survey_hash(int $survey_id, int $course_id, int $session_id, int $group_id): string
1475
    {
1476
        $securityKey = api_get_env_variable('kernel.secret');
1477
1478
        return hash(
1479
            'sha512',
1480
            $securityKey.'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id
1481
        );
1482
    }
1483
1484
    /**
1485
     * @param int    $survey_id
1486
     * @param int    $course_id
1487
     * @param int    $session_id
1488
     * @param int    $group_id
1489
     * @param string $hash
1490
     *
1491
     * @return bool
1492
     */
1493
    public static function validate_survey_hash($survey_id, $course_id, $session_id, $group_id, $hash)
1494
    {
1495
        $generatedHash = self::generate_survey_hash($survey_id, $course_id, $session_id, $group_id);
1496
        if ($generatedHash == $hash) {
1497
            return true;
1498
        }
1499
1500
        return false;
1501
    }
1502
1503
    /**
1504
     * @param int $survey_id
1505
     * @param int $course_id
1506
     * @param int $session_id
1507
     * @param int $group_id
1508
     *
1509
     * @return string
1510
     */
1511
    public static function generate_survey_link(
1512
        $survey_id,
1513
        $course_id,
1514
        $session_id,
1515
        $group_id
1516
    ) {
1517
        $code = self::generate_survey_hash(
1518
            $survey_id,
1519
            $course_id,
1520
            $session_id,
1521
            $group_id
1522
        );
1523
1524
        return api_get_path(WEB_CODE_PATH).'survey/link.php?h='.$code.'&i='.$survey_id.'&c='.intval($course_id).'&s='
1525
            .intval($session_id).'&g='.$group_id;
1526
    }
1527
1528
    /**
1529
     * Check if the current user has mandatory surveys no-answered
1530
     * and redirect to fill the first found survey.
1531
     */
1532
    public static function protectByMandatory()
1533
    {
1534
        if (false !== strpos($_SERVER['SCRIPT_NAME'], 'fillsurvey.php')) {
1535
            return;
1536
        }
1537
1538
        $userId = api_get_user_id();
1539
        $courseId = api_get_course_int_id();
1540
        $sessionId = api_get_session_id();
1541
1542
        if (!$userId) {
1543
            return;
1544
        }
1545
1546
        if (!$courseId) {
1547
            return;
1548
        }
1549
1550
        try {
1551
            /** @var CSurveyInvitation $invitation */
1552
            $invitation = Database::getManager()
1553
                ->createQuery("
1554
                    SELECT i FROM ChamiloCourseBundle:CSurveyInvitation i
1555
                    INNER JOIN ChamiloCourseBundle:CSurvey s
1556
                        WITH (s.code = i.surveyCode AND s.cId = i.cId AND s.sessionId = i.sessionId)
1557
                    INNER JOIN ChamiloCoreBundle:ExtraFieldValues efv WITH efv.itemId = s.iid
1558
                    INNER JOIN ChamiloCoreBundle:ExtraField ef WITH efv.field = ef.id
1559
                    WHERE
1560
                        i.answered = 0 AND
1561
                        i.cId = :course AND
1562
                        i.user = :user AND
1563
                        i.sessionId = :session AND
1564
                        :now BETWEEN s.availFrom AND s.availTill AND
1565
                        ef.variable = :variable AND
1566
                        efv.field_value = 1 AND
1567
                        s.surveyType != 3
1568
                    ORDER BY s.availTill ASC
1569
                ")
1570
                ->setMaxResults(1)
1571
                ->setParameters([
1572
                    'course' => $courseId,
1573
                    'user' => $userId,
1574
                    'session' => $sessionId,
1575
                    'now' => new DateTime('UTC', new DateTimeZone('UTC')),
1576
                    'variable' => 'is_mandatory',
1577
                ])
1578
                ->getSingleResult();
1579
        } catch (Exception $e) {
1580
            $invitation = null;
1581
        }
1582
1583
        if (!$invitation) {
1584
            return;
1585
        }
1586
1587
        Display::addFlash(
1588
            Display::return_message(
1589
                get_lang(
1590
                    'A mandatory survey is waiting your answer. To enter the course, you must first complete the survey.'
1591
                ),
1592
                'warning'
1593
            )
1594
        );
1595
1596
        $url = SurveyUtil::generateFillSurveyLink(
1597
            $invitation->getInvitationCode(),
1598
            api_get_course_info(),
1599
            api_get_session_id()
1600
        );
1601
1602
        header('Location: '.$url);
1603
        exit;
1604
    }
1605
1606
    /**
1607
     * This function empty surveys (invitations and answers).
1608
     *
1609
     * @param int $surveyId id of the survey to empty
1610
     *
1611
     * @return bool
1612
     */
1613
    public static function emptySurveyFromId($surveyId)
1614
    {
1615
        // Database table definitions
1616
        $surveyInvitationTable = Database:: get_course_table(TABLE_SURVEY_INVITATION);
1617
        $surveyAnswerTable = Database:: get_course_table(TABLE_SURVEY_ANSWER);
1618
        $surveyTable = Database:: get_course_table(TABLE_SURVEY);
1619
        $surveyId = (int) $surveyId;
1620
        $surveyData = self::get_survey($surveyId);
1621
        if (empty($surveyData)) {
1622
            return false;
1623
        }
1624
1625
        $surveyCode = $surveyData['survey_code'];
1626
        $courseId = (int) $surveyData['c_id'];
1627
        $sessionId = (int) $surveyData['session_id'];
1628
1629
        $sql = "DELETE FROM $surveyInvitationTable
1630
                WHERE session_id = $sessionId AND c_id = $courseId AND survey_code = '$surveyCode' ";
1631
        Database::query($sql);
1632
1633
        $sql = "DELETE FROM $surveyAnswerTable
1634
                WHERE survey_id = $surveyId AND c_id = $courseId ";
1635
        Database::query($sql);
1636
1637
        $sql = "UPDATE $surveyTable
1638
                SET invited = 0, answered = 0
1639
                WHERE iid = $surveyId AND c_id = $courseId AND session_id = $sessionId ";
1640
        Database::query($sql);
1641
1642
        return true;
1643
    }
1644
1645
    /**
1646
     * Copy/duplicate one question (into the same survey).
1647
     * Note: Relies on the question iid to find all necessary info.
1648
     *
1649
     * @param int $questionId
1650
     *
1651
     * @return int The new question's iid, or 0 on error
1652
     */
1653
    public static function copyQuestion($questionId)
1654
    {
1655
        if (empty($questionId)) {
1656
            return 0;
1657
        }
1658
        $questionId = (int) $questionId;
1659
        $questionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
1660
        $optionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1661
1662
        // Get questions
1663
        $sql = "SELECT * FROM $questionTable WHERE iid = $questionId";
1664
        $res = Database::query($sql);
1665
        if (false == $res) {
1666
            // Could not find this question
1667
            return 0;
1668
        }
1669
        $row = Database::fetch_assoc($res);
1670
        $params = [
1671
            //'c_id' => $row['c_id'],
1672
            'survey_id' => $row['survey_id'],
1673
            'survey_question' => trim($row['survey_question']),
1674
            'survey_question_comment' => $row['survey_question_comment'],
1675
            'type' => $row['type'],
1676
            'display' => $row['display'],
1677
            'shared_question_id' => $row['shared_question_id'],
1678
            'max_value' => $row['max_value'],
1679
            'survey_group_pri' => $row['survey_group_pri'],
1680
            'survey_group_sec1' => $row['survey_group_sec1'],
1681
            'survey_group_sec2' => $row['survey_group_sec2'],
1682
        ];
1683
        if (isset($row['is_required'])) {
1684
            $params['is_required'] = $row['is_required'];
1685
        }
1686
        // Get question position
1687
        $sqlSort = "SELECT max(sort) as sort FROM $questionTable
1688
                    WHERE survey_id = ".$row['survey_id'];
1689
        $resSort = Database::query($sqlSort);
1690
        $rowSort = Database::fetch_assoc($resSort);
1691
        $params['sort'] = $rowSort['sort'] + 1;
1692
        // Insert the new question
1693
        $insertId = Database::insert($questionTable, $params);
1694
        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...
1695
            return 0;
1696
        }
1697
1698
        // Get questions options
1699
        $sql = "SELECT * FROM $optionsTable WHERE question_id = $questionId";
1700
        $res = Database::query($sql);
1701
        while ($row = Database::fetch_assoc($res)) {
1702
            $params = [
1703
                //'c_id' => $row['c_id'],
1704
                'question_id' => $insertId,
1705
                'survey_id' => $row['survey_id'],
1706
                'option_text' => $row['option_text'],
1707
                'sort' => $row['sort'],
1708
                'value' => $row['value'],
1709
            ];
1710
            Database::insert($optionsTable, $params);
1711
        }
1712
1713
        return $insertId;
1714
    }
1715
1716
    /**
1717
     * @param array $surveyData
1718
     *
1719
     * @return bool
1720
     */
1721
    public static function removeMultiplicateQuestions(CSurvey $survey, $courseId)
1722
    {
1723
        $surveyId = $survey->getIid();
1724
        $courseId = (int) $courseId;
1725
1726
        if (empty($surveyId) || empty($courseId)) {
1727
            return false;
1728
        }
1729
1730
        $questions = $survey->getQuestions();
1731
        foreach ($questions as $question) {
1732
            // Questions marked with "geneated" were created using the "multiplicate" feature.
1733
            if ('generated' === $question->getSurveyQuestionComment()) {
1734
                self::deleteQuestion($question->getIid());
1735
            }
1736
        }
1737
    }
1738
1739
    /**
1740
     * @return bool
1741
     */
1742
    public static function multiplicateQuestions(CSurvey $survey, $courseId)
1743
    {
1744
        $surveyId = $survey->getIid();
1745
1746
        if (empty($surveyId)) {
1747
            return false;
1748
        }
1749
1750
        $questions = self::get_questions($surveyId);
1751
1752
        if (empty($questions)) {
1753
            return false;
1754
        }
1755
1756
        $extraFieldValue = new ExtraFieldValue('survey');
1757
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
1758
        $groupId = null;
1759
        if ($groupData && !empty($groupData['value'])) {
1760
            $groupId = (int) $groupData['value'];
1761
        }
1762
1763
        if (null === $groupId) {
1764
            $obj = new UserGroupModel();
1765
            $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...
1766
            $classList = $obj->getUserGroupInCourse($options);
1767
1768
            $classToParse = [];
1769
            foreach ($classList as $class) {
1770
                $users = $obj->get_users_by_usergroup($class['id']);
1771
                if (empty($users)) {
1772
                    continue;
1773
                }
1774
                $classToParse[] = [
1775
                    'name' => $class['name'],
1776
                    'users' => $users,
1777
                ];
1778
            }
1779
            self::parseMultiplicateUserList($classToParse, $questions, $courseId, $survey, true);
1780
        } else {
1781
            $groupInfo = GroupManager::get_group_properties($groupId);
1782
            if (!empty($groupInfo)) {
1783
                $users = GroupManager::getStudents($groupInfo['iid'], true);
1784
                if (!empty($users)) {
1785
                    $users = array_column($users, 'id');
1786
                    self::parseMultiplicateUserList(
1787
                        [
1788
                            [
1789
                                'name' => $groupInfo['name'],
1790
                                'users' => $users,
1791
                            ],
1792
                        ],
1793
                        $questions,
1794
                        $courseId,
1795
                        $survey,
1796
                        false
1797
                    );
1798
                }
1799
            }
1800
        }
1801
1802
        return true;
1803
    }
1804
1805
    public static function parseMultiplicateUserList($itemList, $questions, $courseId, CSurvey $survey, $addClassNewPage = false)
1806
    {
1807
        if (empty($itemList) || empty($questions)) {
1808
            return false;
1809
        }
1810
1811
        $surveyId = $survey->getIid();
1812
        $classTag = '{{class_name}}';
1813
        $studentTag = '{{student_full_name}}';
1814
        $classCounter = 0;
1815
1816
        $newQuestionList = [];
1817
        foreach ($questions as $question) {
1818
            $newQuestionList[$question['sort']] = $question;
1819
        }
1820
        ksort($newQuestionList);
1821
1822
        $order = ('true' === api_get_setting('survey.survey_duplicate_order_by_name'));
1823
        foreach ($itemList as $class) {
1824
            $className = $class['name'];
1825
            $users = $class['users'];
1826
            $userInfoList = [];
1827
            foreach ($users as $userId) {
1828
                $userInfoList[] = api_get_user_info($userId);
1829
            }
1830
1831
            if ($order) {
1832
                usort(
1833
                    $userInfoList,
1834
                    function ($a, $b) {
1835
                        return $a['lastname'] > $b['lastname'];
1836
                    }
1837
                );
1838
            }
1839
1840
            foreach ($newQuestionList as $question) {
1841
                $text = $question['question'];
1842
                if (false !== strpos($text, $classTag)) {
1843
                    $replacedText = str_replace($classTag, $className, $text);
1844
                    $values = [
1845
                        'c_id' => $courseId,
1846
                        'question_comment' => 'generated',
1847
                        'type' => $question['type'],
1848
                        'display' => $question['horizontalvertical'],
1849
                        'horizontalvertical' => $question['horizontalvertical'],
1850
                        'question' => $replacedText,
1851
                        'survey_id' => $surveyId,
1852
                        'question_id' => 0,
1853
                        'shared_question_id' => 0,
1854
                        'answers' => $question['answers'] ?? null,
1855
                    ];
1856
                    self::saveQuestion($survey, $values, false);
1857
                    $classCounter++;
1858
                    continue;
1859
                }
1860
1861
                foreach ($userInfoList as $userInfo) {
1862
                    if (false !== strpos($text, $studentTag)) {
1863
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
1864
                        $values = [
1865
                            'c_id' => $courseId,
1866
                            'question_comment' => 'generated',
1867
                            'type' => $question['type'],
1868
                            'display' => $question['horizontalvertical'],
1869
                            'maximum_score' => $question['maximum_score'],
1870
                            'question' => $replacedText,
1871
                            'survey_id' => $surveyId,
1872
                            'question_id' => 0,
1873
                            'shared_question_id' => 0,
1874
                        ];
1875
1876
                        $answers = [];
1877
                        if (!empty($question['answers'])) {
1878
                            foreach ($question['answers'] as $answer) {
1879
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
1880
                                $answers[] = $replacedText;
1881
                            }
1882
                        }
1883
                        $values['answers'] = $answers;
1884
                        self::saveQuestion($survey, $values, false);
1885
                    }
1886
                }
1887
1888
                if ($addClassNewPage && $classCounter < count($itemList)) {
1889
                    // Add end page
1890
                    $values = [
1891
                        'c_id' => $courseId,
1892
                        'question_comment' => 'generated',
1893
                        'type' => 'pagebreak',
1894
                        'display' => 'horizontal',
1895
                        'question' => get_lang('Question for next class'),
1896
                        'survey_id' => $surveyId,
1897
                        'question_id' => 0,
1898
                        'shared_question_id' => 0,
1899
                    ];
1900
                    self::saveQuestion($survey, $values, false);
1901
                }
1902
            }
1903
        }
1904
1905
        return true;
1906
    }
1907
1908
    public static function hasDependency(CSurvey $survey)
1909
    {
1910
        $surveyId = $survey->getIid();
1911
1912
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1913
        $sql = "SELECT COUNT(iid) count FROM $table
1914
                WHERE
1915
                    survey_id = $surveyId AND
1916
                    parent_option_id <> 0
1917
                LIMIT 1
1918
                ";
1919
        $result = Database::query($sql);
1920
        $row = Database::fetch_array($result);
1921
1922
        if ($row) {
1923
            return $row['count'] > 0;
1924
        }
1925
1926
        return false;
1927
    }
1928
1929
    /**
1930
     * @return int
1931
     */
1932
    public static function getCountPages(CSurvey $survey)
1933
    {
1934
        $surveyId = $survey->getIid();
1935
1936
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1937
1938
        // pagebreak
1939
        $sql = "SELECT COUNT(iid) FROM $table
1940
                WHERE
1941
                    survey_question NOT LIKE '%{{%' AND
1942
                    type = 'pagebreak' AND
1943
                    survey_id = $surveyId";
1944
        $result = Database::query($sql);
1945
        $numberPageBreaks = Database::result($result, 0, 0);
1946
1947
        // No pagebreak
1948
        $sql = "SELECT COUNT(iid) FROM $table
1949
                WHERE
1950
                    survey_question NOT LIKE '%{{%' AND
1951
                    type != 'pagebreak' AND
1952
                    survey_id = $surveyId";
1953
        $result = Database::query($sql);
1954
        $countOfQuestions = Database::result($result, 0, 0);
1955
1956
        if (1 == $survey->getOneQuestionPerPage()) {
1957
            if (!empty($countOfQuestions)) {
1958
                return $countOfQuestions;
1959
            }
1960
1961
            return 1;
1962
        }
1963
1964
        if (empty($numberPageBreaks)) {
1965
            return 1;
1966
        }
1967
1968
        return $numberPageBreaks + 1;
1969
    }
1970
1971
    /**
1972
     * Check whether this survey has ended. If so, display message and exit this script.
1973
     */
1974
    public static function checkTimeAvailability(?CSurvey $survey): void
1975
    {
1976
        if (null === $survey) {
1977
            api_not_allowed(true);
1978
        }
1979
1980
        $utcZone = new DateTimeZone('UTC');
1981
        $startDate = $survey->getAvailFrom();
1982
        $endDate = $survey->getAvailTill();
1983
        $currentDate = new DateTime('now', $utcZone);
1984
        $currentDate->modify('today');
1985
1986
        $returnMessage = false;
1987
        if ($currentDate < $startDate) {
1988
            $returnMessage =  Display:: return_message(
1989
                get_lang('This survey is not yet available. Please try again later. Thank you.'),
1990
                'warning',
1991
                false
1992
            );
1993
        }
1994
1995
        if ($currentDate > $endDate) {
1996
            $returnMessage = Display:: return_message(
1997
                get_lang('Sorry, this survey is not available anymore. Thank you for trying.'),
1998
                'warning',
1999
                false
2000
            );
2001
        }
2002
2003
        if (false !== $returnMessage) {
2004
            $content = Display::page_header($survey->getTitle());
2005
            $content .= $returnMessage;
2006
            $template = new Template();
2007
            $template->assign('actions', Display::toolbarAction('toolbar', []));
2008
            $template->assign('content', $content);
2009
            $template->display_one_col_template();
2010
            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...
2011
        }
2012
    }
2013
2014
    public static function getUserInvitationsForSurveyInCourse(
2015
        int    $userId,
2016
        string $surveyCode,
2017
        int    $courseId,
2018
        int    $sessionId = 0,
2019
        int    $groupId = 0,
2020
        int    $lpItemId = 0
2021
    ): array {
2022
2023
        $em = Database::getManager();
2024
        $invitationRepo = $em->getRepository(CSurveyInvitation::class);
2025
        $surveyRepo = $em->getRepository(CSurvey::class);
2026
2027
        $survey = $surveyRepo->findOneBy(['code' => $surveyCode]);
2028
        if (!$survey) {
2029
            return [];
2030
        }
2031
2032
        $criteria = [
2033
            'user'    => api_get_user_entity($userId),
2034
            'course'  => api_get_course_entity($courseId),
2035
            'session' => api_get_session_entity($sessionId),
2036
            'survey'  => $survey,
2037
        ];
2038
2039
        if (!empty($groupId)) {
2040
            $criteria['group'] = api_get_group_entity($groupId);
2041
        }
2042
2043
        if (is_int($lpItemId) && $lpItemId > 0) {
2044
            $criteria['lpItemId'] = $lpItemId;
2045
        }
2046
2047
        return $invitationRepo->findBy($criteria, ['invitationDate' => 'DESC']);
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([
2069
            'user'     => api_get_user_entity($userId),
2070
            'answered' => $answered ? 1 : 0,
2071
        ]);
2072
        $mainUrl = api_get_path(WEB_CODE_PATH).'survey/survey.php?';
2073
        $content = '';
2074
2075
        if (empty($answered)) {
2076
            $content .= Display::page_subheader(get_lang('Unanswered'));
2077
        } else {
2078
            $content .= Display::page_subheader(get_lang('Answered'));
2079
        }
2080
2081
        if (!empty($invitations)) {
2082
            $table = new HTML_Table(['class' => 'table']);
2083
            $table->setHeaderContents(0, 0, get_lang('Survey name'));
2084
            $table->setHeaderContents(0, 1, get_lang('Course'));
2085
2086
            if (empty($answered)) {
2087
                $table->setHeaderContents(0, 2, get_lang('Survey').' - '.get_lang('End Date'));
2088
            }
2089
2090
            // Not answered
2091
            /** @var CSurveyInvitation $invitation */
2092
            $row = 1;
2093
            foreach ($invitations as $invitation) {
2094
                $course = $invitation->getCourse();
2095
                $courseId = $course->getId();
2096
                $courseCode = $course->getCode();
2097
                $sessionId = $invitation->getSession() ? $invitation->getSession()->getId() : 0;
2098
2099
                if (!empty($answered)) {
2100
                    // check if user is subscribed to the course/session
2101
                    if (empty($sessionId)) {
2102
                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode);
2103
                    } else {
2104
                        $subscribe = CourseManager::is_user_subscribed_in_course(
2105
                            $userId,
2106
                            $courseCode,
2107
                            true,
2108
                            $sessionId
2109
                        );
2110
                    }
2111
2112
                    // User is not subscribe skip!
2113
                    if (empty($subscribe)) {
2114
                        continue;
2115
                    }
2116
                }
2117
2118
                $survey = $invitation->getSurvey();
2119
                if (null === $survey) {
2120
                    continue;
2121
                }
2122
2123
                $url = $mainUrl.'survey_id='.$survey->getIid().'&cid='.$courseId.'&sid='.$sessionId;
2124
                $title = $survey->getTitle();
2125
                $title = Display::url($title, $url);
2126
                $courseTitle = $course->getTitle();
2127
                if (!empty($sessionId)) {
2128
                    $courseTitle .= ' ('.$invitation->getSession()->getTitle().')';
2129
                }
2130
2131
                $surveyData = self::get_survey($survey->getIid(), 0, $courseCode);
2132
                $table->setCellContents($row, 0, $title);
2133
                $table->setCellContents($row, 1, $courseTitle);
2134
2135
                if (empty($answered)) {
2136
                    $table->setHeaderContents(
2137
                        $row,
2138
                        2,
2139
                        api_get_local_time(
2140
                            $survey->getAvailTill(),
2141
                            null,
2142
                            null,
2143
                            true,
2144
                            false
2145
                        )
2146
                    );
2147
                }
2148
2149
                if (!empty($answered) && 0 == $survey->getAnonymous()) {
2150
                    $answers = SurveyUtil::displayCompleteReport(
2151
                        $surveyData,
2152
                        $userId,
2153
                        false,
2154
                        false,
2155
                        false
2156
                    );
2157
                    $table->setCellContents(++$row, 0, $answers);
2158
                    $table->setCellContents(++$row, 1, '');
2159
                }
2160
2161
                $row++;
2162
            }
2163
            $content .= $table->toHtml();
2164
        } else {
2165
            $content .= Display::return_message(get_lang('No data available'));
2166
        }
2167
2168
        return $content;
2169
    }
2170
2171
    public static function sendToTutors(CSurvey $survey)
2172
    {
2173
        $surveyId = $survey->getIid();
2174
2175
        $extraFieldValue = new ExtraFieldValue('survey');
2176
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
2177
        if ($groupData && !empty($groupData['value'])) {
2178
            $groupInfo = GroupManager::get_group_properties($groupData['value']);
2179
            if ($groupInfo) {
2180
                $tutors = GroupManager::getTutors($groupInfo);
2181
                if (!empty($tutors)) {
2182
                    SurveyUtil::saveInviteMail(
2183
                        $survey,
2184
                        ' ',
2185
                        ' ',
2186
                        false
2187
                    );
2188
2189
                    foreach ($tutors as $tutor) {
2190
                        $subject = sprintf(get_lang('Group survey for %s'), $groupInfo['name']);
2191
                        $content = sprintf(
2192
                            get_lang('Hi %s <br/><br/>As group tutor for the group %s you are invited to participate at the following survey :'),
2193
                            $tutor['complete_name'],
2194
                            $groupInfo['name']
2195
                        );
2196
2197
                        SurveyUtil::saveInvitations(
2198
                            $survey,
2199
                            ['users' => $tutor['user_id']],
2200
                            $subject,
2201
                            $content,
2202
                            false,
2203
                            true,
2204
                            false,
2205
                            true
2206
                        );
2207
                    }
2208
                    Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false));
2209
                }
2210
                SurveyUtil::updateInvitedCount($survey);
2211
2212
                return true;
2213
            }
2214
        }
2215
2216
        return false;
2217
    }
2218
2219
    public static function getInvitationsAnswered(
2220
        string $surveyCode,
2221
        int $courseId,
2222
        int $sessionId = 0
2223
    ): array {
2224
        $em = Database::getManager();
2225
2226
        $qb = $em->createQueryBuilder();
2227
        $qb->select('i')
2228
            ->from(CSurveyInvitation::class, 'i')
2229
            ->innerJoin('i.survey', 's')
2230
            ->andWhere('s.code = :code')
2231
            ->andWhere('IDENTITY(i.course) = :courseId')
2232
            ->andWhere('i.answered = 1')
2233
            ->setParameter('code', $surveyCode)
2234
            ->setParameter('courseId', $courseId)
2235
            ->orderBy('i.invitationDate', 'DESC');
2236
2237
        if ($sessionId > 0) {
2238
            $qb->andWhere('IDENTITY(i.session) = :sid')
2239
                ->setParameter('sid', (int) $sessionId);
2240
        } else {
2241
            $qb->andWhere(
2242
                $qb->expr()->orX(
2243
                    'i.session IS NULL',
2244
                    'IDENTITY(i.session) = 0'
2245
                )
2246
            );
2247
        }
2248
2249
        $query = $qb->getQuery();
2250
2251
        return $query->getResult();
2252
    }
2253
}
2254