SurveyManager::saveQuestion()   F
last analyzed

Complexity

Conditions 33
Paths 2381

Size

Total Lines 172
Code Lines 111

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 33
eloc 111
c 0
b 0
f 0
nc 2381
nop 4
dl 0
loc 172
rs 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
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
        $table = Database::get_course_table(TABLE_SURVEY);
36
        $code = Database::escape_string($code);
37
        $num = 0;
38
        $new_code = $code;
39
        while (true) {
40
            if (isset($surveyId)) {
41
                $sql = "SELECT 1 FROM $table WHERE code = '$new_code' AND iid = $surveyId";
42
            } else {
43
                $sql = "SELECT 1 FROM $table WHERE code = '$new_code'";
44
            }
45
46
            $result = Database::query($sql);
47
            if (Database::num_rows($result)) {
48
                $num++;
49
                $new_code = $code.$num;
50
            } else {
51
                break;
52
            }
53
        }
54
55
        return $code.$num;
56
    }
57
58
    /**
59
     * Deletes all survey invitations of a user.
60
     *
61
     * @param int $user_id
62
     *
63
     * @return bool
64
     * @assert ('') === false
65
     */
66
    public static function delete_all_survey_invitations_by_user($user_id)
67
    {
68
        $user_id = (int) $user_id;
69
        if (empty($user_id)) {
70
            return false;
71
        }
72
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
73
        $table_survey = Database::get_course_table(TABLE_SURVEY);
74
75
        $sql = "SELECT iid, survey_id
76
                FROM $table_survey_invitation WHERE user_id = '$user_id' AND c_id <> 0 ";
77
        $result = Database::query($sql);
78
        while ($row = Database::fetch_assoc($result)) {
79
            $survey_invitation_id = $row['iid'];
80
            $surveyId = $row['survey_id'];
81
            $sql2 = "DELETE FROM $table_survey_invitation
82
                     WHERE iid = '$survey_invitation_id' AND c_id <> 0";
83
            if (Database::query($sql2)) {
84
                $sql3 = "UPDATE $table_survey SET
85
                            invited = invited - 1
86
                         WHERE  iid = $surveyId";
87
                Database::query($sql3);
88
            }
89
        }
90
    }
91
92
    /**
93
     * @param string $course_code
94
     * @param int    $session_id
95
     *
96
     * @return array
97
     * @assert ('') === false
98
     */
99
    public static function get_surveys($courseCode, int $sessionId = 0)
100
    {
101
        $courseId = api_get_course_int_id();
102
        $repo = Container::getSurveyRepository();
103
        $course = api_get_course_entity($courseId);
104
        $session = api_get_session_entity($sessionId);
105
106
        $qb = $repo->getResourcesByCourse($course, $session, null, null, true, true);
107
108
        return $qb->getQuery()->getArrayResult();
109
    }
110
111
    /**
112
     * Retrieves all the survey information.
113
     *
114
     * @param int $survey_id the id of the survey
115
     * @param int $shared    this parameter determines if
116
     *                       we have to get the information of a survey from the central (shared) database or from the
117
     *                       course database
118
     * @param string course code optional
119
     *
120
     * @author Patrick Cool <[email protected]>, Ghent University
121
     *
122
     * @version February 2007
123
     * @assert ('') === false
124
     *
125
     * @return array
126
     *
127
     * @todo this is the same function as in create_new_survey.php
128
     */
129
    public static function get_survey(
130
        $survey_id,
131
        $shared = 0,
132
        $course_code = '',
133
        $simple_return = false
134
    ) {
135
        $courseInfo = api_get_course_info();
136
        $survey_id = (int) $survey_id;
137
        $table_survey = Database::get_course_table(TABLE_SURVEY);
138
139
        if (empty($courseInfo) || empty($survey_id)) {
140
            return [];
141
        }
142
143
        $sql = "SELECT * FROM $table_survey WHERE iid = $survey_id";
144
        $result = Database::query($sql);
145
        $return = [];
146
147
        if (Database::num_rows($result) > 0) {
148
            $return = Database::fetch_assoc($result);
149
            if ($simple_return) {
150
                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...
151
            }
152
            $return['survey_code']           = $return['code'];
153
            $return['survey_title']          = $return['title'];
154
            $return['survey_subtitle']       = $return['subtitle'];
155
            $return['survey_language']       = $return['lang'];
156
            $return['start_date']            = $return['avail_from'];
157
            $return['end_date']              = $return['avail_till'];
158
            $return['survey_share']          = $return['is_shared'];
159
            $return['survey_introduction']   = $return['intro'];
160
            $return['survey_thanks']         = $return['surveythanks'];
161
            $return['input_name_list']       = $return['input_name_list'] ?? null;
162
            $return['c_id']                  = $return['c_id'] ?? 0;
163
            $return['session_id']            = $return['session_id'] ?? 0;
164
        }
165
166
        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...
167
    }
168
169
    /**
170
     * @param string $code
171
     *
172
     * @return string
173
     */
174
    public static function generateSurveyCode($code)
175
    {
176
        return strtolower(CourseManager::generate_course_code($code));
177
    }
178
179
    /**
180
     * This function stores a survey in the database.
181
     *
182
     * @param array $values
183
     *
184
     * @return array $return the type of return message that has to be displayed and the message in it
185
     *
186
     * @author Patrick Cool <[email protected]>, Ghent University
187
     *
188
     * @version February 2007
189
     */
190
    public static function store_survey($values)
191
    {
192
        $return = ['id' => 0];
193
        $session_id = api_get_session_id();
194
        $table_survey = Database::get_course_table(TABLE_SURVEY);
195
        $shared_survey_id = 0;
196
        $displayQuestionNumber = isset($values['display_question_number']);
197
        $repo = Container::getSurveyRepository();
198
199
        if (empty($values['survey_id'])) {
200
            $normalizedCode = self::generateSurveyCode($values['survey_code'] ?? '');
201
            $lang = $values['survey_language'] ?? api_get_language_isocode();
202
203
            $sql = 'SELECT 1 FROM '.$table_survey.'
204
                WHERE code = "'.Database::escape_string($normalizedCode).'"
205
                  AND lang = "'.Database::escape_string($lang).'"';
206
            $rs = Database::query($sql);
207
            if (Database::num_rows($rs) > 0) {
208
                Display::addFlash(
209
                    Display::return_message(get_lang('This survey code soon exists in this language'), 'error')
210
                );
211
                return ['type' => 'error', 'id' => 0];
212
            }
213
214
            $values['anonymous'] = !empty($values['anonymous']) ? 1 : 0;
215
            $onePerPage = !empty($values['one_question_per_page']) ? 1 : 0;
216
            $shuffle    = !empty($values['shuffle']) ? 1 : 0;
217
218
            $survey = new CSurvey();
219
            if (0 == $values['anonymous']) {
220
                $values['show_form_profile'] = !empty($values['show_form_profile']) ? 1 : 0;
221
                $survey->setShowFormProfile($values['show_form_profile']);
222
223
                if (1 == $values['show_form_profile']) {
224
                    $fields = explode(',', $values['input_name_list'] ?? '');
225
                    $field_values = '';
226
                    foreach ($fields as $field) {
227
                        if ($field === '') { continue; }
228
                        $v = isset($values[$field]) && $values[$field] !== '' ? $values[$field] : 0;
229
                        $field_values .= $field.':'.$v.'@';
230
                    }
231
                    $survey->setFormFields($field_values);
232
                } else {
233
                    $survey->setFormFields('');
234
                }
235
            } else {
236
                $survey->setFormFields('');
237
                $survey->setShowFormProfile(0);
238
            }
239
240
            try {
241
                $start = new \DateTime($values['start_date']);
242
                $end   = new \DateTime($values['end_date']);
243
            } catch (\Exception $e) {
244
                Display::addFlash(Display::return_message(get_lang('Invalid date'), 'error'));
245
                return ['type' => 'error', 'id' => 0];
246
            }
247
248
            $course  = api_get_course_entity();
249
            $session = api_get_session_entity();
250
251
            $survey
252
                ->setCode($normalizedCode)
253
                ->setTitle($values['survey_title'])
254
                ->setSubtitle($values['survey_subtitle'] ?? '')
255
                ->setLang($lang)
256
                ->setAvailFrom($start)
257
                ->setAvailTill($end)
258
                ->setIsShared($shared_survey_id)
259
                ->setTemplate('template')
260
                ->setIntro($values['survey_introduction'])
261
                ->setSurveyThanks($values['survey_thanks'])
262
                ->setDisplayQuestionNumber($displayQuestionNumber)
263
                ->setAnonymous((string) ((int) $values['anonymous']))
264
                ->setVisibleResults((int) ($values['visible_results'] ?? SURVEY_VISIBLE_TUTOR))
265
                ->setSurveyType((int) ($values['survey_type'] ?? 0))
266
                ->setOneQuestionPerPage($onePerPage)
267
                ->setShuffle($shuffle)
268
                ->setParent($course)
269
                ->addCourseLink($course, $session);
270
271
            if (!empty($values['parent_id'])) {
272
                $parent = $repo->find((int) $values['parent_id']);
273
                if ($parent) {
274
                    $survey->setSurveyParent($parent);
275
                }
276
            }
277
278
            $repo->create($survey);
279
            $survey_id = (int) $survey->getIid();
280
281
            if ($survey_id > 0) {
282
                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

282
                Event::/** @scrutinizer ignore-call */ 
283
                       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...
283
                    LOG_SURVEY_CREATED,
284
                    LOG_SURVEY_ID,
285
                    $survey_id,
286
                    null,
287
                    api_get_user_id(),
288
                    api_get_course_int_id(),
289
                    api_get_session_id()
290
                );
291
            }
292
293
            if ((int) ($values['survey_type'] ?? 0) === 1 && !empty($values['parent_id'])) {
294
                self::copySurvey((int) $values['parent_id'], $survey_id);
295
            }
296
297
            Display::addFlash(
298
                Display::return_message(get_lang('The survey has been created successfully'), 'success')
299
            );
300
            $return['id'] = $survey_id;
301
        } else {
302
            $surveyId = (int) $values['survey_id'];
303
304
            /** @var CSurvey $survey */
305
            $survey = $repo->find($surveyId);
306
            if (!$survey) {
0 ignored issues
show
introduced by
$survey is of type Chamilo\CourseBundle\Entity\CSurvey, thus it always evaluated to true.
Loading history...
307
                Display::addFlash(Display::return_message(get_lang('Survey not found'), 'error'));
308
                return ['type' => 'error', 'id' => $surveyId];
309
            }
310
311
            $inputCode = isset($values['survey_code']) ? self::generateSurveyCode($values['survey_code']) : $survey->getCode();
312
            $inputLang = $values['survey_language'] ?? $survey->getLang();
313
            $codeChanged = ($inputCode !== $survey->getCode()) || ($inputLang !== $survey->getLang());
314
315
            if ($codeChanged) {
316
                $sql = 'SELECT 1 FROM '.$table_survey.'
317
                    WHERE code = "'.Database::escape_string($inputCode).'"
318
                      AND lang = "'.Database::escape_string($inputLang).'"
319
                      AND iid <> '.(int) $surveyId;
320
                $rs = Database::query($sql);
321
                if (Database::num_rows($rs) > 0) {
322
                    Display::addFlash(
323
                        Display::return_message(get_lang('This survey code soon exists in this language'), 'error')
324
                    );
325
                    return ['type' => 'error', 'id' => $surveyId];
326
                }
327
                // Aplica nuevo code/lang si cambiaron
328
                $survey->setCode($inputCode);
329
                $survey->setLang($inputLang);
330
            }
331
332
            $values['anonymous']     = !empty($values['anonymous']) ? 1 : 0;
333
            $onePerPage              = !empty($values['one_question_per_page']) ? 1 : 0;
334
            $shuffle                 = !empty($values['shuffle']) ? 1 : 0;
335
            $showFormProfile         = !empty($values['show_form_profile']) ? 1 : 0;
336
337
            try {
338
                $start = !empty($values['start_date']) ? new \DateTime($values['start_date']) : $survey->getAvailFrom();
339
                $end   = !empty($values['end_date'])   ? new \DateTime($values['end_date'])   : $survey->getAvailTill();
340
            } catch (\Exception $e) {
341
                Display::addFlash(Display::return_message(get_lang('Invalid date'), 'error'));
342
                return ['type' => 'error', 'id' => $surveyId];
343
            }
344
345
            if (0 == $values['anonymous']) {
346
                $survey->setShowFormProfile($showFormProfile);
347
                if (1 == $showFormProfile) {
348
                    $fields = explode(',', $values['input_name_list'] ?? '');
349
                    $field_values = '';
350
                    foreach ($fields as $field) {
351
                        if ($field === '') { continue; }
352
                        $v = isset($values[$field]) && $values[$field] !== '' ? $values[$field] : 0;
353
                        $field_values .= $field.':'.$v.'@';
354
                    }
355
                    $survey->setFormFields($field_values);
356
                } else {
357
                    $survey->setFormFields('');
358
                }
359
            } else {
360
                $survey->setFormFields('');
361
                $survey->setShowFormProfile(0);
362
            }
363
364
            $survey
365
                ->setTitle($values['survey_title'])
366
                ->setSubtitle($values['survey_subtitle'] ?? '')
367
                ->setAvailFrom($start)
368
                ->setAvailTill($end)
369
                ->setIsShared($shared_survey_id)
370
                ->setTemplate('template')
371
                ->setIntro($values['survey_introduction'])
372
                ->setSurveyThanks($values['survey_thanks'])
373
                ->setAnonymous((string) ((int) $values['anonymous']))
374
                ->setVisibleResults((int) ($values['visible_results'] ?? SURVEY_VISIBLE_TUTOR))
375
                ->setDisplayQuestionNumber($displayQuestionNumber)
376
                ->setOneQuestionPerPage($onePerPage)
377
                ->setShuffle($shuffle);
378
379
            $em = Database::getManager();
380
            $em->persist($survey);
381
            $em->flush();
382
383
            Display::addFlash(
384
                Display::return_message(get_lang('The survey has been updated successfully'), 'confirmation')
385
            );
386
            $return['id'] = $surveyId;
387
        }
388
389
        $survey_id = (int) $return['id'];
390
        $gradebook_option = !empty($values['survey_qualify_gradebook']);
391
        $gradebook_link_type = 8;
392
        $link_info = GradebookUtils::isResourceInCourseGradebook(
393
            api_get_course_int_id(),
394
            $gradebook_link_type,
395
            $survey_id,
396
            $session_id
397
        );
398
        $gradebook_link_id = $link_info['id'] ?? false;
399
400
        if ($gradebook_option) {
401
            $survey_weight = isset($values['survey_weight'])
402
                ? (float) $values['survey_weight']
403
                : (isset($_POST['survey_weight']) ? (float) $_POST['survey_weight'] : 0.0);
404
            $max_score = 1;
405
406
            if (!$gradebook_link_id && isset($values['category_id'])) {
407
                GradebookUtils::add_resource_to_course_gradebook(
408
                    $values['category_id'],
409
                    api_get_course_int_id(),
410
                    $gradebook_link_type,
411
                    $survey_id,
412
                    '',
413
                    $survey_weight,
414
                    $max_score,
415
                    '',
416
                    1,
417
                    $session_id
418
                );
419
            } else {
420
                GradebookUtils::updateResourceFromCourseGradebook(
421
                    $gradebook_link_id,
422
                    api_get_course_int_id(),
423
                    $survey_weight
424
                );
425
            }
426
        } else {
427
            // Delete everything of the gradebook for this $linkId
428
            GradebookUtils::remove_resource_from_course_gradebook($gradebook_link_id);
429
        }
430
431
        return $return;
432
    }
433
434
    public static function deleteSurvey(CSurvey $survey)
435
    {
436
        $repo = Container::getSurveyRepository();
437
        $surveyId = $survey->getIid();
438
        $repo->delete($survey);
439
440
        $table_survey = Database::get_course_table(TABLE_SURVEY);
441
        $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
442
443
        Event::addEvent(
444
            LOG_SURVEY_DELETED,
445
            LOG_SURVEY_ID,
446
            $surveyId,
447
            null,
448
            api_get_user_id(),
449
            api_get_course_int_id(),
450
            api_get_session_id()
451
        );
452
453
        /*// Deleting groups of this survey
454
        $sql = "DELETE FROM $table_survey_question_group
455
                WHERE c_id = $course_id AND iid='".$survey_id."'";
456
        Database::query($sql);*/
457
458
        // Deleting the questions of the survey
459
        self::delete_all_survey_questions($surveyId, false);
460
461
        // Update into item_property (delete)
462
        /*api_item_property_update(
463
            $course_info,
464
            TOOL_SURVEY,
465
            $survey_id,
466
            'SurveyDeleted',
467
            api_get_user_id()
468
        );*/
469
470
        SkillModel::deleteSkillsFromItem($surveyId, ITEM_TYPE_SURVEY);
471
472
        return true;
473
    }
474
475
    /**
476
     * Copy given survey to a new (optional) given survey ID.
477
     */
478
    public static function copySurvey(
479
        int $surveyId,
480
        ?int $newSurveyId = null,
481
        ?int $targetCourseId = null,
482
        ?int $targetSessionId = null
483
    ): ?int {
484
        $originalCourseId = api_get_course_int_id();
485
        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...
486
            $targetCourseId = $originalCourseId;
487
        }
488
489
        $repo = Container::getSurveyRepository();
490
491
        $surveyTable = Database::get_course_table(TABLE_SURVEY);
492
        $surveyQuestionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
493
        $surveyOptionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
494
495
        $surveyData = self::get_survey($surveyId, 0, null, true);
496
        if (empty($surveyData)) {
497
            return null;
498
        }
499
500
        if (empty($newSurveyId)) {
501
            $surveyData['code'] = self::generate_unique_code($surveyData['code']);
502
            $surveyData['session_id'] = $targetSessionId ?? api_get_session_id();
503
504
            if ($targetCourseId === $originalCourseId) {
505
                $surveyData['title'] .= ' '.get_lang('Copy');
506
            }
507
508
            unset($surveyData['iid'], $surveyData['id']);
509
510
            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...
511
                $newSurveyId = Database::insert($surveyTable, $surveyData);
512
            } else {
513
                $course = api_get_course_entity();
514
                $session = api_get_session_entity();
515
516
                $survey = new CSurvey();
517
                $survey
518
                    ->setSurveyType($surveyData['survey_type'])
519
                    ->setSurveyVersion($surveyData['survey_version'])
520
                    ->setCode($surveyData['code'])
521
                    ->setTitle($surveyData['title'])
522
                    ->setSubtitle($surveyData['subtitle'])
523
                    ->setLang($surveyData['lang'])
524
                    ->setAvailFrom(new \DateTime($surveyData['avail_from']))
525
                    ->setAvailTill(new \DateTime($surveyData['avail_till']))
526
                    ->setIsShared($surveyData['is_shared'])
527
                    ->setTemplate($surveyData['template'])
528
                    ->setIntro($surveyData['intro'])
529
                    ->setSurveyThanks($surveyData['surveythanks'])
530
                    ->setAnonymous($surveyData['anonymous'])
531
                    ->setVisibleResults($surveyData['visible_results'])
532
                    ->setShuffle($surveyData['shuffle'])
533
                    ->setOneQuestionPerPage($surveyData['one_question_per_page'])
534
                    ->setShowFormProfile($surveyData['show_form_profile'])
535
                    ->setFormFields($surveyData['form_fields'])
536
                    ->setParent($course)
537
                    ->addCourseLink($course, $session);
538
539
                if (!empty($surveyData['parent_id'])) {
540
                    $parent = $repo->find($surveyData['parent_id']);
541
                    if ($parent) {
542
                        $survey->setSurveyParent($parent);
543
                    }
544
                }
545
546
                $repo->create($survey);
547
                $newSurveyId = $survey->getIid();
548
            }
549
        }
550
551
        if (empty($newSurveyId)) {
552
            return null;
553
        }
554
555
        $sql = "SELECT * FROM $surveyQuestionTable WHERE survey_id = $surveyId";
556
        $res = Database::query($sql);
557
        $question_id = [];
558
        while ($row = Database::fetch_assoc($res)) {
559
            $params = [
560
                'survey_id' => $newSurveyId,
561
                'survey_question' => $row['survey_question'],
562
                'survey_question_comment' => $row['survey_question_comment'],
563
                'type' => $row['type'],
564
                'display' => $row['display'],
565
                'sort' => $row['sort'],
566
                'shared_question_id' => $row['shared_question_id'],
567
                'max_value' => $row['max_value'],
568
                'survey_group_pri' => $row['survey_group_pri'],
569
                'survey_group_sec1' => $row['survey_group_sec1'],
570
                'survey_group_sec2' => $row['survey_group_sec2'],
571
            ];
572
573
            if (isset($row['is_required'])) {
574
                $params['is_required'] = $row['is_required'];
575
            }
576
577
            $insertId = Database::insert($surveyQuestionTable, $params);
578
            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...
579
                $question_id[$row['iid']] = $insertId;
580
            }
581
        }
582
583
        $sql = "SELECT * FROM $surveyOptionsTable WHERE survey_id = $surveyId";
584
        $res = Database::query($sql);
585
        while ($row = Database::fetch_assoc($res)) {
586
            $params = [
587
                'question_id' => $question_id[$row['question_id']] ?? 0,
588
                'survey_id' => $newSurveyId,
589
                'option_text' => $row['option_text'],
590
                'sort' => $row['sort'],
591
                'value' => $row['value'],
592
            ];
593
            Database::insert($surveyOptionsTable, $params);
594
        }
595
596
        return $newSurveyId;
597
    }
598
599
    /**
600
     * This function duplicates a survey (and also all the question in that survey.
601
     *
602
     * @param int $surveyId id of the survey that has to be duplicated
603
     * @param int $courseId id of the course which survey has to be duplicated
604
     *
605
     * @return true
606
     *
607
     * @author Eric Marguin <[email protected]>, Elixir Interactive
608
     *
609
     * @version October 2007
610
     */
611
    public static function empty_survey($surveyId, $courseId = 0)
612
    {
613
        // Database table definitions
614
        $table_survey_invitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
615
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
616
        $table_survey = Database::get_course_table(TABLE_SURVEY);
617
618
        $courseId = (int) $courseId;
619
        $courseId = empty($courseId) ? api_get_course_int_id() : $courseId;
620
        $surveyId = (int) $surveyId;
621
622
        $datas = self::get_survey($surveyId);
623
        $session_where = '';
624
        if (0 != api_get_session_id()) {
625
            $session_where = ' AND session_id = "'.api_get_session_id().'" ';
626
        }
627
628
        $sql = 'DELETE FROM '.$table_survey_invitation.'
629
		        WHERE
630
		            survey_id = "'.$surveyId.'" '.$session_where.' ';
631
        Database::query($sql);
632
633
        $sql = 'DELETE FROM '.$table_survey_answer.'
634
		        WHERE
635
		        survey_id = "'.$surveyId.'" '.$session_where.' ';
636
        Database::query($sql);
637
638
        $sql = 'UPDATE '.$table_survey.' SET invited=0, answered=0
639
		        WHERE iid ='.$surveyId;
640
        Database::query($sql);
641
642
        Event::addEvent(
643
            LOG_SURVEY_CLEAN_RESULTS,
644
            LOG_SURVEY_ID,
645
            $surveyId,
646
            null,
647
            api_get_user_id(),
648
            api_get_course_int_id(),
649
            api_get_session_id()
650
        );
651
652
        return true;
653
    }
654
655
    /**
656
     * Updates c_survey.answered: number of people who have taken the survey (=filled at least one question).
657
     */
658
    public static function updateSurveyAnswered(CSurvey $survey, $user, $lpItemId = 0): void
659
    {
660
        $em = Database::getManager();
661
        $surveyId  = (int) $survey->getIid();
662
        $courseId  = (int) api_get_course_int_id();
663
        $sessionId = api_get_session_id();
664
665
        $survey->setAnswered($survey->getAnswered() + 1);
666
        $em->persist($survey);
667
        $em->flush();
668
669
        $lpItemCondition = $lpItemId ? ' AND c_lp_item_id = '.(int) $lpItemId : '';
670
671
        $sessionWhere = $sessionId > 0
672
            ? 'session_id = '.$sessionId
673
            : '(session_id IS NULL OR session_id = 0)';
674
675
        $courseWhere = $courseId > 0 ? ' AND c_id = '.$courseId : '';
676
677
        $userId = is_numeric($user) ? (int) $user : (int) api_get_user_id();
678
679
        $table = Database::get_course_table(TABLE_SURVEY_INVITATION);
680
        $sql = "UPDATE $table
681
            SET answered_at = '".api_get_utc_datetime()."', answered = 1
682
            WHERE $sessionWhere
683
              AND user_id = $userId
684
              AND survey_id = $surveyId
685
              $courseWhere
686
              $lpItemCondition";
687
        Database::query($sql);
688
    }
689
690
    /**
691
     * This function return the "icon" of the question type.
692
     *
693
     * @param string $type
694
     *
695
     * @author Patrick Cool <[email protected]>, Ghent University
696
     *
697
     * @version February 2007
698
     */
699
    public static function icon_question($type)
700
    {
701
        // the possible question types
702
        $possible_types = [
703
            'personality',
704
            'yesno',
705
            'multiplechoice',
706
            'multipleresponse',
707
            'open',
708
            'dropdown',
709
            'comment',
710
            'pagebreak',
711
            'percentage',
712
            'score',
713
        ];
714
715
        // the images array
716
        $icon_question = [
717
            'yesno' => 'thumbs-up-down',
718
            'personality' => 'thumbs-up-down',
719
            'multiplechoice' => 'format-list-bulleted',
720
            'multipleresponse' => 'format-list-bulleted-square',
721
            'open' => 'form-textarea',
722
            'dropdown' => 'form-dropdown',
723
            'percentage' => 'percent-box-outline',
724
            'score' => 'format-annotation-plus',
725
            'comment' => 'format-align-top',
726
            'pagebreak' => 'format-page-break',
727
        ];
728
729
        if (in_array($type, $possible_types)) {
730
            return $icon_question[$type];
731
        }
732
733
        return false;
734
    }
735
736
    /**
737
     * This function retrieves all the information of a question.
738
     *
739
     * @param int  $question_id the id of the question
740
     * @param bool $shared
741
     *
742
     * @return array
743
     *
744
     * @author Patrick Cool <[email protected]>, Ghent University
745
     *
746
     * @version January 2007
747
     *
748
     * @todo one sql call should do the trick
749
     */
750
    public static function get_question($question_id)
751
    {
752
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
753
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
754
        $course_id = api_get_course_int_id();
755
        $question_id = (int) $question_id;
756
757
        if (empty($question_id)) {
758
            return [];
759
        }
760
761
        $sql = "SELECT * FROM $tbl_survey_question
762
                WHERE iid = $question_id
763
                ORDER BY `sort` ";
764
765
        $sqlOption = "  SELECT * FROM $table_survey_question_option
766
                        WHERE question_id='".$question_id."'
767
                        ORDER BY `sort` ";
768
        // Getting the information of the question
769
        $result = Database::query($sql);
770
        $row = Database::fetch_assoc($result);
771
772
        $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...
773
        $return['parent_id'] = isset($row['parent_id']) ? $row['parent_id'] : 0;
774
        $return['parent_option_id'] = isset($row['parent_option_id']) ? $row['parent_option_id'] : 0;
775
        $return['question_id'] = $row['iid'];
776
        $return['type'] = $row['type'];
777
        $return['question'] = $row['survey_question'];
778
        $return['horizontalvertical'] = $row['display'];
779
        $return['shared_question_id'] = $row['shared_question_id'];
780
        $return['maximum_score'] = $row['max_value'];
781
        $return['is_required'] = $row['is_required'];
782
783
        if (0 != $row['survey_group_pri']) {
784
            $return['assigned'] = $row['survey_group_pri'];
785
            $return['choose'] = 1;
786
        } else {
787
            $return['assigned1'] = $row['survey_group_sec1'];
788
            $return['assigned2'] = $row['survey_group_sec2'];
789
            $return['choose'] = 2;
790
        }
791
792
        // Getting the information of the question options
793
        $result = Database::query($sqlOption);
794
        $counter = 0;
795
        while ($row = Database::fetch_assoc($result)) {
796
            /** @todo this should be renamed to options instead of answers */
797
            $return['answers'][] = $row['option_text'];
798
            $return['values'][] = $row['value'];
799
            $return['answer_data'][$counter]['data'] = $row['option_text'];
800
            $return['answer_data'][$counter]['iid'] = $row['iid'];
801
            /** @todo this can be done more elegantly (used in reporting) */
802
            $return['answersid'][] = $row['iid'];
803
            $counter++;
804
        }
805
806
        return $return;
807
    }
808
809
    /**
810
     * This function gets all the question of any given survey.
811
     *
812
     * @param int $surveyId the id of the survey
813
     * @param int $courseId
814
     *
815
     * @return array containing all the questions of the survey
816
     *
817
     * @author Patrick Cool <[email protected]>, Ghent University
818
     *
819
     * @version February 2007
820
     *
821
     * @todo one sql call should do the trick
822
     */
823
    public static function get_questions($surveyId, $courseId = 0)
824
    {
825
        $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
826
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
827
828
        $courseId = (int) $courseId;
829
        $surveyId = (int) $surveyId;
830
831
        // Getting the information of the question
832
        $sql = "SELECT * FROM $tbl_survey_question
833
		        WHERE survey_id= $surveyId ";
834
        $result = Database::query($sql);
835
        $questions = [];
836
        while ($row = Database::fetch_assoc($result)) {
837
            $questionId = $row['iid'];
838
            $questions[$questionId]['survey_id'] = $surveyId;
839
            $questions[$questionId]['question_id'] = $questionId;
840
            $questions[$questionId]['type'] = $row['type'];
841
            $questions[$questionId]['question'] = $row['survey_question'];
842
            $questions[$questionId]['horizontalvertical'] = $row['display'];
843
            $questions[$questionId]['maximum_score'] = $row['max_value'];
844
            $questions[$questionId]['sort'] = $row['sort'];
845
            $questions[$questionId]['survey_question_comment'] = $row['survey_question_comment'];
846
847
            // Getting the information of the question options
848
            $sql = "SELECT * FROM $table_survey_question_option
849
		             WHERE survey_id= $surveyId  AND question_id = $questionId";
850
            $resultOptions = Database::query($sql);
851
            while ($rowOption = Database::fetch_assoc($resultOptions)) {
852
                $questions[$questionId]['answers'][] = $rowOption['option_text'];
853
            }
854
        }
855
856
        return $questions;
857
    }
858
859
    public static function saveQuestion(CSurvey $survey, array $form_content, bool $showMessage = true, array $dataFromDatabase = [])
860
    {
861
        $surveyId = $survey->getIid();
862
863
        $error = false;
864
        $message = '';
865
        if (strlen($form_content['question']) > 1) {
866
            // Checks length of the question
867
            $empty_answer = false;
868
            if (1 == $survey->getSurveyType()) {
869
                if (empty($form_content['choose'])) {
870
                    return 'PleaseChooseACondition';
871
                }
872
873
                if ((2 == $form_content['choose']) &&
874
                    ($form_content['assigned1'] == $form_content['assigned2'])
875
                ) {
876
                    return 'ChooseDifferentCategories';
877
                }
878
            }
879
880
            if ('percentage' !== $form_content['type']) {
881
                if (isset($form_content['answers'])) {
882
                    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...
883
                        if (strlen($form_content['answers'][$i]) < 1) {
884
                            $empty_answer = true;
885
                            break;
886
                        }
887
                    }
888
                }
889
            }
890
891
            if ('score' === $form_content['type']) {
892
                if (strlen($form_content['maximum_score']) < 1) {
893
                    $empty_answer = true;
894
                }
895
            }
896
897
            $em = Database::getManager();
898
            $course_id = api_get_course_int_id();
899
            if (!$empty_answer) {
900
                // Table definitions
901
                $tbl_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
902
903
                // Getting all the information of the survey
904
                $survey_data = self::get_survey($surveyId);
905
906
                // Storing a new question
907
                if (empty($form_content['question_id']) || !is_numeric($form_content['question_id'])) {
908
                    // Finding the max sort order of the questions in the given survey
909
                    $sql = "SELECT max(sort) AS max_sort
910
					        FROM $tbl_survey_question
911
                            WHERE survey_id = $surveyId ";
912
                    $result = Database::query($sql);
913
                    $row = Database::fetch_assoc($result);
914
                    $max_sort = $row['max_sort'];
915
916
                    $question = new CSurveyQuestion();
917
918
                    // Some variables defined for survey-test type
919
                    if (isset($_POST['choose'])) {
920
                        if (1 == $_POST['choose']) {
921
                            $question->setSurveyGroupPri($_POST['assigned']);
922
                        } elseif (2 == $_POST['choose']) {
923
                            $question->setSurveyGroupSec1($_POST['assigned1']);
924
                            $question->setSurveyGroupSec2($_POST['assigned2']);
925
                        }
926
                    }
927
928
                    $question
929
                        ->setSurveyQuestionComment($form_content['question_comment'] ?? '')
930
                        ->setMaxValue($form_content['maximum_score'] ?? 0)
931
                        ->setDisplay($form_content['horizontalvertical'] ?? '')
932
                        //->setCId($course_id)
933
                        ->setSurvey($survey)
934
                        ->setSurveyQuestion($form_content['question'])
935
                        ->setType($form_content['type'])
936
                        ->setSort($max_sort + 1)
937
                        ->setSharedQuestionId((int) $form_content['shared_question_id'])
938
                    ;
939
940
                    $question->setIsMandatory(isset($form_content['is_required']));
941
942
                    $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...
943
                    $params['parent_option_id'] = 0;
944
                    if (isset($form_content['parent_id']) &&
945
                        isset($form_content['parent_option_id']) &&
946
                        !empty($form_content['parent_id']) &&
947
                        !empty($form_content['parent_option_id'])
948
                    ) {
949
                        $params['parent_id'] = $form_content['parent_id'];
950
                        $params['parent_option_id'] = $form_content['parent_option_id'];
951
                    }
952
953
                    $em->persist($question);
954
                    $em->flush();
955
956
                    $question_id = $question->getIid();
957
                    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...
958
                        /*$sql = "UPDATE $tbl_survey_question SET question_id = $question_id
959
                                WHERE iid = $question_id";
960
                        Database::query($sql);*/
961
                        $form_content['question_id'] = $question_id;
962
                        $message = 'The question has been added.';
963
                        $error = false;
964
                    }
965
                } else {
966
                    $repo = $em->getRepository(CSurveyQuestion::class);
967
                    $repoOption = $em->getRepository(CSurveyQuestionOption::class);
968
                    /** @var CSurveyQuestion $question */
969
                    $question = $repo->find($form_content['question_id']);
970
971
                    if (isset($_POST['choose'])) {
972
                        if (1 == $_POST['choose']) {
973
                            $question->setSurveyGroupPri($_POST['assigned']);
974
                            $question->setSurveyGroupSec1(0);
975
                            $question->setSurveyGroupSec2(0);
976
                        } elseif (2 == $_POST['choose']) {
977
                            $question->setSurveyGroupPri(0);
978
                            $question->setSurveyGroupSec1($_POST['assigned1']);
979
                            $question->setSurveyGroupSec2($_POST['assigned2']);
980
                        }
981
                    }
982
983
                    $maxScore = isset($form_content['maximum_score']) ? (int) $form_content['maximum_score'] : 0;
984
                    $questionComment = $form_content['question_comment'] ?? '';
985
                    $question
986
                        ->setSurveyQuestionComment($questionComment)
987
                        ->setSurveyQuestion($form_content['question'])
988
                        ->setDisplay($form_content['horizontalvertical'])
989
                        ->setMaxValue($maxScore)
990
                    ;
991
992
                    $question->isMandatory(isset($form_content['is_required']));
993
                    $params['parent_id'] = 0;
994
                    $params['parent_option_id'] = 0;
995
                    if (isset($form_content['parent_id']) &&
996
                        isset($form_content['parent_option_id']) &&
997
                        !empty($form_content['parent_id']) &&
998
                        !empty($form_content['parent_option_id'])
999
                    ) {
1000
                        $question->setParent($repo->find($form_content['parent_id']));
1001
                        $question->setParentOption($repoOption->find($form_content['parent_option_id']));
1002
                    }
1003
1004
                    $em->persist($question);
1005
                    $em->flush();
1006
                    $message = 'QuestionUpdated';
1007
                    $error = false;
1008
                }
1009
                // Storing the options of the question
1010
                self::saveQuestionOptions($survey, $question, $form_content, $dataFromDatabase);
1011
            } else {
1012
                $message = 'PleasFillAllAnswer';
1013
                $error = true;
1014
            }
1015
        } else {
1016
            $message = 'PleaseEnterAQuestion';
1017
            $error = true;
1018
        }
1019
1020
        if ($showMessage) {
1021
            if (!empty($message)) {
1022
                Display::addFlash(Display::return_message(get_lang($message)));
1023
            }
1024
        }
1025
        $result = [
1026
            'error' => $error,
1027
            'message' => $message,
1028
        ];
1029
1030
        return $result;
1031
    }
1032
1033
    /**
1034
     * Moves a survey question within the ordered list.
1035
     *
1036
     * @param string $direction The direction to move the question ('moveup' or 'movedown').
1037
     * @param int    $surveyQuestionId The ID of the survey question to move.
1038
     * @param int    $surveyId The ID of the survey to which the question belongs.
1039
     */
1040
    public static function moveSurveyQuestion(string $direction, int $surveyQuestionId, int $surveyId): void
1041
    {
1042
        $em = Database::getManager();
1043
        $repo = $em->getRepository(CSurveyQuestion::class);
1044
        $sortDirection = $direction === 'moveup' ? 'DESC' : 'ASC';
1045
        $questions = $repo->findBy(['survey' => $surveyId], ['sort' => $sortDirection]);
1046
1047
        $found = false;
1048
        foreach ($questions as $question) {
1049
            if ($found) {
1050
                $secondQuestion = $question;
1051
                $found = false;
1052
                break;
1053
            }
1054
            if ($question->getIid() == $surveyQuestionId) {
1055
                $found = true;
1056
                $firstQuestion = $question;
1057
            }
1058
        }
1059
1060
        if (isset($firstQuestion) && isset($secondQuestion)) {
1061
            $tempSort = $firstQuestion->getSort();
1062
            $firstQuestion->setSort($secondQuestion->getSort());
1063
            $secondQuestion->setSort($tempSort);
1064
1065
            $em->persist($firstQuestion);
1066
            $em->persist($secondQuestion);
1067
            $em->flush();
1068
        }
1069
    }
1070
1071
    /**
1072
     * This function deletes all the questions of a given survey
1073
     * This function is normally only called when a survey is deleted.
1074
     *
1075
     * @param int $survey_id the id of the survey that has to be deleted
1076
     *
1077
     * @return bool
1078
     *
1079
     * @author Patrick Cool <[email protected]>, Ghent University
1080
     *
1081
     * @version January 2007
1082
     */
1083
    public static function delete_all_survey_questions($survey_id, $shared = false)
1084
    {
1085
        $course_id = api_get_course_int_id();
1086
        $survey_id = (int) $survey_id;
1087
1088
        /*$sql = "DELETE FROM $table_survey_question
1089
                WHERE $course_condition survey_id = '".$survey_id."'";
1090
1091
        // Deleting the survey questions
1092
        Database::query($sql);*/
1093
1094
        // Deleting all the options of the questions of the survey
1095
        //self::delete_all_survey_questions_options($survey_id, $shared);
1096
1097
        // Deleting all the answers on this survey
1098
        //self::delete_all_survey_answers($survey_id);
1099
1100
        return true;
1101
    }
1102
1103
    public static function deleteQuestion($questionId)
1104
    {
1105
        $questionId = (int) $questionId;
1106
        if (empty($questionId)) {
1107
            return false;
1108
        }
1109
1110
        $em = Database::getManager();
1111
        $repo = Container::getSurveyQuestionRepository();
1112
        $question = $repo->find($questionId);
1113
        if ($question) {
1114
            $em->remove($question);
1115
            $em->flush();
1116
1117
            return true;
1118
        }
1119
1120
        return false;
1121
    }
1122
1123
    public static function saveQuestionOptions(CSurvey $survey, CSurveyQuestion $question, $form_content, $dataFromDatabase = [])
1124
    {
1125
        $course_id = api_get_course_int_id();
1126
        $type = $form_content['type'];
1127
1128
        // A percentage question type has options 1 -> 100
1129
        if ('percentage' === $type) {
1130
            for ($i = 1; $i < 101; $i++) {
1131
                $form_content['answers'][] = $i;
1132
            }
1133
        }
1134
        $em = Database::getManager();
1135
1136
        // Table definition
1137
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1138
1139
        // We are editing a question so we first have to remove all the existing options from the database
1140
        $optionsToDelete = [];
1141
        if (isset($dataFromDatabase['answer_data'])) {
1142
            foreach ($dataFromDatabase['answer_data'] as $data) {
1143
                if ('other' === $data['data'] && 'multiplechoiceother' === $type) {
1144
                    continue;
1145
                }
1146
1147
                if (!in_array($data['iid'], $form_content['answersid'])) {
1148
                    $optionsToDelete[] = $data['iid'];
1149
                }
1150
            }
1151
        }
1152
1153
        if (!empty($optionsToDelete)) {
1154
            foreach ($optionsToDelete as $iid) {
1155
                $iid = (int) $iid;
1156
                $sql = "DELETE FROM $table
1157
			            WHERE
1158
			                iid = $iid AND
1159
                            question_id = '".intval($form_content['question_id'])."'
1160
                            ";
1161
                Database::query($sql);
1162
            }
1163
        }
1164
1165
        $counter = 1;
1166
        if (isset($form_content['answers']) && is_array($form_content['answers'])) {
1167
            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...
1168
                $values = isset($form_content['values']) ? (int) $form_content['values'][$i] : 0;
1169
                $answerId = 0;
1170
                if (isset($form_content['answersid']) && isset($form_content['answersid'][$i])) {
1171
                    $answerId = $form_content['answersid'][$i];
1172
                }
1173
                if (empty($answerId)) {
1174
                    $option = new CSurveyQuestionOption();
1175
                    $option
1176
                        ->setQuestion($question)
1177
                        ->setOptionText($form_content['answers'][$i])
1178
                        ->setSurvey($survey)
1179
                        ->setValue($values)
1180
                        ->setSort($counter)
1181
                    ;
1182
                    $em->persist($option);
1183
                    $em->flush();
1184
                    $insertId = $option->getIid();
1185
                    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...
1186
                        $counter++;
1187
                    }
1188
                } else {
1189
                    $repo = $em->getRepository(CSurveyQuestionOption::class);
1190
                    /** @var CSurveyQuestionOption $option */
1191
                    $option = $repo->find($answerId);
1192
                    if ($option) {
1193
                        $option
1194
                            ->setOptionText($form_content['answers'][$i])
1195
                            ->setValue($values)
1196
                            ->setSort($counter)
1197
                        ;
1198
                        $em->persist($option);
1199
                        $em->flush();
1200
                    }
1201
                    $counter++;
1202
                }
1203
            }
1204
        }
1205
1206
        if ('multiplechoiceother' === $type) {
1207
            if (empty($dataFromDatabase['answer_data'])) {
1208
                $params = [
1209
                    'question_id' => $form_content['question_id'],
1210
                    'survey_id' => $form_content['survey_id'],
1211
                    'option_text' => 'other',
1212
                    'value' => 0,
1213
                    'sort' => $counter,
1214
                ];
1215
                Database::insert($table, $params);
1216
            } else {
1217
                $params = [
1218
                    'option_text' => 'other',
1219
                    'value' => 0,
1220
                    'sort' => $counter,
1221
                ];
1222
                Database::update(
1223
                    $table,
1224
                    $params,
1225
                    [
1226
                        'question_id = ? AND survey_id = ? AND option_text = ?' => [
1227
                            $form_content['question_id'],
1228
                            $form_content['survey_id'],
1229
                            'other',
1230
                        ],
1231
                    ]
1232
                );
1233
            }
1234
        }
1235
    }
1236
1237
    /**
1238
     * This function deletes all the options of the questions of a given survey
1239
     * This function is normally only called when a survey is deleted.
1240
     *
1241
     * @param int $survey_id the id of the survey that has to be deleted
1242
     *
1243
     * @return true
1244
     *
1245
     * @author Patrick Cool <[email protected]>, Ghent University
1246
     *
1247
     * @version January 2007
1248
     */
1249
    public static function delete_all_survey_questions_options($survey_id, $shared = false)
1250
    {
1251
        // Table definitions
1252
        $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1253
        $course_id = api_get_course_int_id();
1254
        $course_condition = " c_id = $course_id AND ";
1255
        $sql = "DELETE FROM $table_survey_question_option
1256
                WHERE $course_condition survey_id='".intval($survey_id)."'";
1257
1258
        // Deleting the options of the survey questions
1259
        Database::query($sql);
1260
1261
        return true;
1262
    }
1263
1264
    /**
1265
     * SURVEY ANSWERS FUNCTIONS.
1266
     */
1267
1268
    /**
1269
     * This function deletes all the answers anyone has given on this survey
1270
     * This function is normally only called when a survey is deleted.
1271
     *
1272
     * @param $survey_id the id of the survey that has to be deleted
1273
     *
1274
     * @return true
1275
     *
1276
     * @todo write the function
1277
     *
1278
     * @author Patrick Cool <[email protected]>, Ghent University
1279
     *
1280
     * @version January 2007,december 2008
1281
     */
1282
    public static function delete_all_survey_answers($survey_id)
1283
    {
1284
        $course_id = api_get_course_int_id();
1285
        $table = Database::get_course_table(TABLE_SURVEY_ANSWER);
1286
        $survey_id = (int) $survey_id;
1287
        $sql = "DELETE FROM $table
1288
                WHERE c_id = $course_id AND survey_id = $survey_id";
1289
        Database::query($sql);
1290
1291
        return true;
1292
    }
1293
1294
    /**
1295
     * This function gets all the persons who have filled the survey.
1296
     *
1297
     * @param int $survey_id
1298
     *
1299
     * @return array
1300
     *
1301
     * @author Patrick Cool <[email protected]>, Ghent University
1302
     *
1303
     * @version February 2007
1304
     */
1305
    public static function get_people_who_filled_survey(
1306
        $survey_id,
1307
        $all_user_info = false,
1308
        $course_id = null
1309
    ) {
1310
        // Database table definition
1311
        $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER);
1312
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1313
1314
        // Variable initialisation
1315
        $return = [];
1316
1317
        if (empty($course_id)) {
1318
            $course_id = api_get_course_int_id();
1319
        } else {
1320
            $course_id = (int) $course_id;
1321
        }
1322
1323
        $survey_id = (int) $survey_id;
1324
1325
        if ($all_user_info) {
1326
            $order_clause = api_sort_by_first_name()
1327
                ? ' ORDER BY user.firstname, user.lastname'
1328
                : ' ORDER BY user.lastname, user.firstname';
1329
            $sql = "SELECT DISTINCT
1330
			            answered_user.user as invited_user,
1331
			            user.firstname,
1332
			            user.lastname,
1333
			            user.id as user_id
1334
                    FROM $table_survey_answer answered_user
1335
                    LEFT JOIN $table_user as user
1336
                    ON answered_user.user = user.id
1337
                    WHERE
1338
                        survey_id= '".$survey_id."' ".
1339
                $order_clause;
1340
        } else {
1341
            $sql = "SELECT DISTINCT user FROM $table_survey_answer
1342
			        WHERE survey_id= '".$survey_id."'  ";
1343
1344
            if ('true' === api_get_setting('survey.survey_anonymous_show_answered')) {
1345
                $tblInvitation = Database::get_course_table(TABLE_SURVEY_INVITATION);
1346
                $tblSurvey = Database::get_course_table(TABLE_SURVEY);
1347
1348
                $sql = "SELECT i.user_id FROM $tblInvitation i
1349
                    INNER JOIN $tblSurvey s
1350
                    ON i.survey_code = s.code
1351
                    WHERE i.answered IS TRUE AND s.iid = $survey_id";
1352
            }
1353
        }
1354
1355
        $res = Database::query($sql);
1356
        while ($row = Database::fetch_assoc($res)) {
1357
            if ($all_user_info) {
1358
                $userInfo = api_get_user_info($row['user_id']);
1359
                $row['user_info'] = $userInfo;
1360
                $return[] = $row;
1361
            } else {
1362
                $return[] = $row['user'];
1363
            }
1364
        }
1365
1366
        return $return;
1367
    }
1368
1369
    /**
1370
     * @return bool
1371
     */
1372
    public static function survey_generation_hash_available()
1373
    {
1374
        if (extension_loaded('mcrypt')) {
1375
            return true;
1376
        }
1377
1378
        return false;
1379
    }
1380
1381
    /**
1382
     * @param int $survey_id
1383
     * @param int $course_id
1384
     * @param int $session_id
1385
     * @param int $group_id
1386
     *
1387
     * @return string
1388
     */
1389
    public static function generate_survey_hash(int $survey_id, int $course_id, int $session_id, int $group_id): string
1390
    {
1391
        $securityKey = api_get_env_variable('kernel.secret');
1392
1393
        return hash(
1394
            'sha512',
1395
            $securityKey.'_'.$course_id.'_'.$session_id.'_'.$group_id.'_'.$survey_id
1396
        );
1397
    }
1398
1399
    /**
1400
     * @param int    $survey_id
1401
     * @param int    $course_id
1402
     * @param int    $session_id
1403
     * @param int    $group_id
1404
     * @param string $hash
1405
     *
1406
     * @return bool
1407
     */
1408
    public static function validate_survey_hash($survey_id, $course_id, $session_id, $group_id, $hash)
1409
    {
1410
        $generatedHash = self::generate_survey_hash($survey_id, $course_id, $session_id, $group_id);
1411
        if ($generatedHash == $hash) {
1412
            return true;
1413
        }
1414
1415
        return false;
1416
    }
1417
1418
    /**
1419
     * @param int $survey_id
1420
     * @param int $course_id
1421
     * @param int $session_id
1422
     * @param int $group_id
1423
     *
1424
     * @return string
1425
     */
1426
    public static function generate_survey_link(
1427
        $survey_id,
1428
        $course_id,
1429
        $session_id,
1430
        $group_id
1431
    ) {
1432
        $code = self::generate_survey_hash(
1433
            $survey_id,
1434
            $course_id,
1435
            $session_id,
1436
            $group_id
1437
        );
1438
1439
        return api_get_path(WEB_CODE_PATH).'survey/link.php?h='.$code.'&i='.$survey_id.'&c='.intval($course_id).'&s='
1440
            .intval($session_id).'&g='.$group_id;
1441
    }
1442
1443
    /**
1444
     * Check if the current user has mandatory surveys no-answered
1445
     * and redirect to fill the first found survey.
1446
     */
1447
    public static function protectByMandatory()
1448
    {
1449
        if (false !== strpos($_SERVER['SCRIPT_NAME'], 'fillsurvey.php')) {
1450
            return;
1451
        }
1452
1453
        $userId = api_get_user_id();
1454
        $courseId = api_get_course_int_id();
1455
        $sessionId = api_get_session_id();
1456
1457
        if (!$userId) {
1458
            return;
1459
        }
1460
1461
        if (!$courseId) {
1462
            return;
1463
        }
1464
1465
        try {
1466
            /** @var CSurveyInvitation $invitation */
1467
            $invitation = Database::getManager()
1468
                ->createQuery("
1469
                    SELECT i FROM ChamiloCourseBundle:CSurveyInvitation i
1470
                    INNER JOIN ChamiloCourseBundle:CSurvey s
1471
                        WITH (s.code = i.surveyCode AND s.cId = i.cId AND s.sessionId = i.sessionId)
1472
                    INNER JOIN ChamiloCoreBundle:ExtraFieldValues efv WITH efv.itemId = s.iid
1473
                    INNER JOIN ChamiloCoreBundle:ExtraField ef WITH efv.field = ef.id
1474
                    WHERE
1475
                        i.answered = 0 AND
1476
                        i.cId = :course AND
1477
                        i.user = :user AND
1478
                        i.sessionId = :session AND
1479
                        :now BETWEEN s.availFrom AND s.availTill AND
1480
                        ef.variable = :variable AND
1481
                        efv.field_value = 1 AND
1482
                        s.surveyType != 3
1483
                    ORDER BY s.availTill ASC
1484
                ")
1485
                ->setMaxResults(1)
1486
                ->setParameters([
1487
                    'course' => $courseId,
1488
                    'user' => $userId,
1489
                    'session' => $sessionId,
1490
                    'now' => new DateTime('UTC', new DateTimeZone('UTC')),
1491
                    'variable' => 'is_mandatory',
1492
                ])
1493
                ->getSingleResult();
1494
        } catch (Exception $e) {
1495
            $invitation = null;
1496
        }
1497
1498
        if (!$invitation) {
1499
            return;
1500
        }
1501
1502
        Display::addFlash(
1503
            Display::return_message(
1504
                get_lang(
1505
                    'A mandatory survey is waiting your answer. To enter the course, you must first complete the survey.'
1506
                ),
1507
                'warning'
1508
            )
1509
        );
1510
1511
        $url = SurveyUtil::generateFillSurveyLink(
1512
            $invitation->getInvitationCode(),
1513
            api_get_course_info(),
1514
            api_get_session_id()
1515
        );
1516
1517
        header('Location: '.$url);
1518
        exit;
1519
    }
1520
1521
    /**
1522
     * This function empty surveys (invitations and answers).
1523
     *
1524
     * @param int $surveyId id of the survey to empty
1525
     *
1526
     * @return bool
1527
     */
1528
    public static function emptySurveyFromId($surveyId)
1529
    {
1530
        // Database table definitions
1531
        $surveyInvitationTable = Database:: get_course_table(TABLE_SURVEY_INVITATION);
1532
        $surveyAnswerTable = Database:: get_course_table(TABLE_SURVEY_ANSWER);
1533
        $surveyTable = Database:: get_course_table(TABLE_SURVEY);
1534
        $surveyId = (int) $surveyId;
1535
        $surveyData = self::get_survey($surveyId);
1536
        if (empty($surveyData)) {
1537
            return false;
1538
        }
1539
1540
        $surveyCode = $surveyData['survey_code'];
1541
        $courseId = (int) $surveyData['c_id'];
1542
        $sessionId = (int) $surveyData['session_id'];
1543
1544
        $sql = "DELETE FROM $surveyInvitationTable
1545
                WHERE session_id = $sessionId AND c_id = $courseId AND survey_code = '$surveyCode' ";
1546
        Database::query($sql);
1547
1548
        $sql = "DELETE FROM $surveyAnswerTable
1549
                WHERE survey_id = $surveyId AND c_id = $courseId ";
1550
        Database::query($sql);
1551
1552
        $sql = "UPDATE $surveyTable
1553
                SET invited = 0, answered = 0
1554
                WHERE iid = $surveyId AND c_id = $courseId AND session_id = $sessionId ";
1555
        Database::query($sql);
1556
1557
        return true;
1558
    }
1559
1560
    /**
1561
     * Copy/duplicate one question (into the same survey).
1562
     * Note: Relies on the question iid to find all necessary info.
1563
     *
1564
     * @param int $questionId
1565
     *
1566
     * @return int The new question's iid, or 0 on error
1567
     */
1568
    public static function copyQuestion($questionId)
1569
    {
1570
        if (empty($questionId)) {
1571
            return 0;
1572
        }
1573
        $questionId = (int) $questionId;
1574
        $questionTable = Database::get_course_table(TABLE_SURVEY_QUESTION);
1575
        $optionsTable = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1576
1577
        // Get questions
1578
        $sql = "SELECT * FROM $questionTable WHERE iid = $questionId";
1579
        $res = Database::query($sql);
1580
        if (false == $res) {
1581
            // Could not find this question
1582
            return 0;
1583
        }
1584
        $row = Database::fetch_assoc($res);
1585
        $params = [
1586
            //'c_id' => $row['c_id'],
1587
            'survey_id' => $row['survey_id'],
1588
            'survey_question' => trim($row['survey_question']),
1589
            'survey_question_comment' => $row['survey_question_comment'],
1590
            'type' => $row['type'],
1591
            'display' => $row['display'],
1592
            'shared_question_id' => $row['shared_question_id'],
1593
            'max_value' => $row['max_value'],
1594
            'survey_group_pri' => $row['survey_group_pri'],
1595
            'survey_group_sec1' => $row['survey_group_sec1'],
1596
            'survey_group_sec2' => $row['survey_group_sec2'],
1597
        ];
1598
        if (isset($row['is_required'])) {
1599
            $params['is_required'] = $row['is_required'];
1600
        }
1601
        // Get question position
1602
        $sqlSort = "SELECT max(sort) as sort FROM $questionTable
1603
                    WHERE survey_id = ".$row['survey_id'];
1604
        $resSort = Database::query($sqlSort);
1605
        $rowSort = Database::fetch_assoc($resSort);
1606
        $params['sort'] = $rowSort['sort'] + 1;
1607
        // Insert the new question
1608
        $insertId = Database::insert($questionTable, $params);
1609
        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...
1610
            return 0;
1611
        }
1612
1613
        // Get questions options
1614
        $sql = "SELECT * FROM $optionsTable WHERE question_id = $questionId";
1615
        $res = Database::query($sql);
1616
        while ($row = Database::fetch_assoc($res)) {
1617
            $params = [
1618
                //'c_id' => $row['c_id'],
1619
                'question_id' => $insertId,
1620
                'survey_id' => $row['survey_id'],
1621
                'option_text' => $row['option_text'],
1622
                'sort' => $row['sort'],
1623
                'value' => $row['value'],
1624
            ];
1625
            Database::insert($optionsTable, $params);
1626
        }
1627
1628
        return $insertId;
1629
    }
1630
1631
    /**
1632
     * @param array $surveyData
1633
     *
1634
     * @return bool
1635
     */
1636
    public static function removeMultiplicateQuestions(CSurvey $survey, $courseId)
1637
    {
1638
        $surveyId = $survey->getIid();
1639
        $courseId = (int) $courseId;
1640
1641
        if (empty($surveyId) || empty($courseId)) {
1642
            return false;
1643
        }
1644
1645
        $questions = $survey->getQuestions();
1646
        foreach ($questions as $question) {
1647
            // Questions marked with "geneated" were created using the "multiplicate" feature.
1648
            if ('generated' === $question->getSurveyQuestionComment()) {
1649
                self::deleteQuestion($question->getIid());
1650
            }
1651
        }
1652
    }
1653
1654
    /**
1655
     * @return bool
1656
     */
1657
    public static function multiplicateQuestions(CSurvey $survey, $courseId)
1658
    {
1659
        $surveyId = $survey->getIid();
1660
1661
        if (empty($surveyId)) {
1662
            return false;
1663
        }
1664
1665
        $questions = self::get_questions($surveyId);
1666
1667
        if (empty($questions)) {
1668
            return false;
1669
        }
1670
1671
        $extraFieldValue = new ExtraFieldValue('survey');
1672
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
1673
        $groupId = null;
1674
        if ($groupData && !empty($groupData['value'])) {
1675
            $groupId = (int) $groupData['value'];
1676
        }
1677
1678
        if (null === $groupId) {
1679
            $obj = new UserGroupModel();
1680
            $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...
1681
            $classList = $obj->getUserGroupInCourse($options);
1682
1683
            $classToParse = [];
1684
            foreach ($classList as $class) {
1685
                $users = $obj->get_users_by_usergroup($class['id']);
1686
                if (empty($users)) {
1687
                    continue;
1688
                }
1689
                $classToParse[] = [
1690
                    'name' => $class['name'],
1691
                    'users' => $users,
1692
                ];
1693
            }
1694
            self::parseMultiplicateUserList($classToParse, $questions, $courseId, $survey, true);
1695
        } else {
1696
            $groupInfo = GroupManager::get_group_properties($groupId);
1697
            if (!empty($groupInfo)) {
1698
                $users = GroupManager::getStudents($groupInfo['iid'], true);
1699
                if (!empty($users)) {
1700
                    $users = array_column($users, 'id');
1701
                    self::parseMultiplicateUserList(
1702
                        [
1703
                            [
1704
                                'name' => $groupInfo['name'],
1705
                                'users' => $users,
1706
                            ],
1707
                        ],
1708
                        $questions,
1709
                        $courseId,
1710
                        $survey,
1711
                        false
1712
                    );
1713
                }
1714
            }
1715
        }
1716
1717
        return true;
1718
    }
1719
1720
    public static function parseMultiplicateUserList($itemList, $questions, $courseId, CSurvey $survey, $addClassNewPage = false)
1721
    {
1722
        if (empty($itemList) || empty($questions)) {
1723
            return false;
1724
        }
1725
1726
        $surveyId = $survey->getIid();
1727
        $classTag = '{{class_name}}';
1728
        $studentTag = '{{student_full_name}}';
1729
        $classCounter = 0;
1730
1731
        $newQuestionList = [];
1732
        foreach ($questions as $question) {
1733
            $newQuestionList[$question['sort']] = $question;
1734
        }
1735
        ksort($newQuestionList);
1736
1737
        $order = ('true' === api_get_setting('survey.survey_duplicate_order_by_name'));
1738
        foreach ($itemList as $class) {
1739
            $className = $class['name'];
1740
            $users = $class['users'];
1741
            $userInfoList = [];
1742
            foreach ($users as $userId) {
1743
                $userInfoList[] = api_get_user_info($userId);
1744
            }
1745
1746
            if ($order) {
1747
                usort(
1748
                    $userInfoList,
1749
                    function ($a, $b) {
1750
                        return $a['lastname'] > $b['lastname'];
1751
                    }
1752
                );
1753
            }
1754
1755
            foreach ($newQuestionList as $question) {
1756
                $text = $question['question'];
1757
                if (false !== strpos($text, $classTag)) {
1758
                    $replacedText = str_replace($classTag, $className, $text);
1759
                    $values = [
1760
                        'c_id' => $courseId,
1761
                        'question_comment' => 'generated',
1762
                        'type' => $question['type'],
1763
                        'display' => $question['horizontalvertical'],
1764
                        'horizontalvertical' => $question['horizontalvertical'],
1765
                        'question' => $replacedText,
1766
                        'survey_id' => $surveyId,
1767
                        'question_id' => 0,
1768
                        'shared_question_id' => 0,
1769
                        'answers' => $question['answers'] ?? null,
1770
                    ];
1771
                    self::saveQuestion($survey, $values, false);
1772
                    $classCounter++;
1773
                    continue;
1774
                }
1775
1776
                foreach ($userInfoList as $userInfo) {
1777
                    if (false !== strpos($text, $studentTag)) {
1778
                        $replacedText = str_replace($studentTag, $userInfo['complete_name'], $text);
1779
                        $values = [
1780
                            'c_id' => $courseId,
1781
                            'question_comment' => 'generated',
1782
                            'type' => $question['type'],
1783
                            'display' => $question['horizontalvertical'],
1784
                            'maximum_score' => $question['maximum_score'],
1785
                            'question' => $replacedText,
1786
                            'survey_id' => $surveyId,
1787
                            'question_id' => 0,
1788
                            'shared_question_id' => 0,
1789
                        ];
1790
1791
                        $answers = [];
1792
                        if (!empty($question['answers'])) {
1793
                            foreach ($question['answers'] as $answer) {
1794
                                $replacedText = str_replace($studentTag, $userInfo['complete_name'], $answer);
1795
                                $answers[] = $replacedText;
1796
                            }
1797
                        }
1798
                        $values['answers'] = $answers;
1799
                        self::saveQuestion($survey, $values, false);
1800
                    }
1801
                }
1802
1803
                if ($addClassNewPage && $classCounter < count($itemList)) {
1804
                    // Add end page
1805
                    $values = [
1806
                        'c_id' => $courseId,
1807
                        'question_comment' => 'generated',
1808
                        'type' => 'pagebreak',
1809
                        'display' => 'horizontal',
1810
                        'question' => get_lang('Question for next class'),
1811
                        'survey_id' => $surveyId,
1812
                        'question_id' => 0,
1813
                        'shared_question_id' => 0,
1814
                    ];
1815
                    self::saveQuestion($survey, $values, false);
1816
                }
1817
            }
1818
        }
1819
1820
        return true;
1821
    }
1822
1823
    public static function hasDependency(CSurvey $survey)
1824
    {
1825
        $surveyId = $survey->getIid();
1826
1827
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1828
        $sql = "SELECT COUNT(iid) count FROM $table
1829
                WHERE
1830
                    survey_id = $surveyId AND
1831
                    parent_option_id <> 0
1832
                LIMIT 1
1833
                ";
1834
        $result = Database::query($sql);
1835
        $row = Database::fetch_array($result);
1836
1837
        if ($row) {
1838
            return $row['count'] > 0;
1839
        }
1840
1841
        return false;
1842
    }
1843
1844
    /**
1845
     * @return int
1846
     */
1847
    public static function getCountPages(CSurvey $survey)
1848
    {
1849
        $surveyId = $survey->getIid();
1850
1851
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
1852
1853
        // pagebreak
1854
        $sql = "SELECT COUNT(iid) FROM $table
1855
                WHERE
1856
                    survey_question NOT LIKE '%{{%' AND
1857
                    type = 'pagebreak' AND
1858
                    survey_id = $surveyId";
1859
        $result = Database::query($sql);
1860
        $numberPageBreaks = Database::result($result, 0, 0);
1861
1862
        // No pagebreak
1863
        $sql = "SELECT COUNT(iid) FROM $table
1864
                WHERE
1865
                    survey_question NOT LIKE '%{{%' AND
1866
                    type != 'pagebreak' AND
1867
                    survey_id = $surveyId";
1868
        $result = Database::query($sql);
1869
        $countOfQuestions = Database::result($result, 0, 0);
1870
1871
        if (1 == $survey->getOneQuestionPerPage()) {
1872
            if (!empty($countOfQuestions)) {
1873
                return $countOfQuestions;
1874
            }
1875
1876
            return 1;
1877
        }
1878
1879
        if (empty($numberPageBreaks)) {
1880
            return 1;
1881
        }
1882
1883
        return $numberPageBreaks + 1;
1884
    }
1885
1886
    /**
1887
     * Check whether this survey has ended. If so, display message and exit this script.
1888
     */
1889
    public static function checkTimeAvailability(?CSurvey $survey): void
1890
    {
1891
        if (null === $survey) {
1892
            api_not_allowed(true);
1893
        }
1894
1895
        if (api_is_allowed_to_edit()) {
1896
            return;
1897
        }
1898
1899
        $utcZone = new DateTimeZone('UTC');
1900
        $startDate = $survey->getAvailFrom();
1901
        $endDate = $survey->getAvailTill();
1902
        $currentDate = new DateTime('now', $utcZone);
1903
        $currentDate->modify('today');
1904
1905
        $returnMessage = false;
1906
        if ($currentDate < $startDate) {
1907
            $returnMessage =  Display:: return_message(
1908
                get_lang('This survey is not yet available. Please try again later. Thank you.'),
1909
                'warning',
1910
                false
1911
            );
1912
        }
1913
1914
        if ($currentDate > $endDate) {
1915
            $returnMessage = Display:: return_message(
1916
                get_lang('Sorry, this survey is not available anymore. Thank you for trying.'),
1917
                'warning',
1918
                false
1919
            );
1920
        }
1921
1922
        if (false !== $returnMessage) {
1923
            $content = Display::page_header($survey->getTitle());
1924
            $content .= $returnMessage;
1925
            $template = new Template();
1926
            $template->assign('actions', Display::toolbarAction('toolbar', []));
1927
            $template->assign('content', $content);
1928
            $template->display_one_col_template();
1929
            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...
1930
        }
1931
    }
1932
1933
    public static function getUserInvitationsForSurveyInCourse(
1934
        int    $userId,
1935
        string $surveyCode,
1936
        int    $courseId,
1937
        int    $sessionId = 0,
1938
        int    $groupId = 0,
1939
        int    $lpItemId = 0
1940
    ): array {
1941
1942
        $em = Database::getManager();
1943
        $invitationRepo = $em->getRepository(CSurveyInvitation::class);
1944
        $surveyRepo = $em->getRepository(CSurvey::class);
1945
1946
        $survey = $surveyRepo->findOneBy(['code' => $surveyCode]);
1947
        if (!$survey) {
1948
            return [];
1949
        }
1950
1951
        $criteria = [
1952
            'user'    => api_get_user_entity($userId),
1953
            'course'  => api_get_course_entity($courseId),
1954
            'session' => api_get_session_entity($sessionId),
1955
            'survey'  => $survey,
1956
        ];
1957
1958
        if (!empty($groupId)) {
1959
            $criteria['group'] = api_get_group_entity($groupId);
1960
        }
1961
1962
        if (is_int($lpItemId) && $lpItemId > 0) {
1963
            $criteria['lpItemId'] = $lpItemId;
1964
        }
1965
1966
        return $invitationRepo->findBy($criteria, ['invitationDate' => 'DESC']);
1967
    }
1968
1969
    /**
1970
     * @param array $userInfo
1971
     * @param int   $answered (1 = answered 0 = not answered)
1972
     *
1973
     * @return string
1974
     */
1975
    public static function surveyReport($userInfo, $answered = 0)
1976
    {
1977
        $userId = isset($userInfo['user_id']) ? (int) $userInfo['user_id'] : 0;
1978
        $answered = (int) $answered;
1979
1980
        if (empty($userId)) {
1981
            return '';
1982
        }
1983
1984
        $em = Database::getManager();
1985
        $repo = $em->getRepository(CSurveyInvitation::class);
1986
        $repoSurvey = $em->getRepository(CSurvey::class);
1987
        $invitations = $repo->findBy([
1988
            'user'     => api_get_user_entity($userId),
1989
            'answered' => $answered ? 1 : 0,
1990
        ]);
1991
        $mainUrl = api_get_path(WEB_CODE_PATH).'survey/survey.php?';
1992
        $content = '';
1993
1994
        if (empty($answered)) {
1995
            $content .= Display::page_subheader(get_lang('Unanswered'));
1996
        } else {
1997
            $content .= Display::page_subheader(get_lang('Answered'));
1998
        }
1999
2000
        if (!empty($invitations)) {
2001
            $table = new HTML_Table(['class' => 'table']);
2002
            $table->setHeaderContents(0, 0, get_lang('Survey name'));
2003
            $table->setHeaderContents(0, 1, get_lang('Course'));
2004
2005
            if (empty($answered)) {
2006
                $table->setHeaderContents(0, 2, get_lang('Survey').' - '.get_lang('End Date'));
2007
            }
2008
2009
            // Not answered
2010
            /** @var CSurveyInvitation $invitation */
2011
            $row = 1;
2012
            foreach ($invitations as $invitation) {
2013
                $course = $invitation->getCourse();
2014
                $courseId = $course->getId();
2015
                $courseCode = $course->getCode();
2016
                $sessionId = $invitation->getSession() ? $invitation->getSession()->getId() : 0;
2017
2018
                if (!empty($answered)) {
2019
                    // check if user is subscribed to the course/session
2020
                    if (empty($sessionId)) {
2021
                        $subscribe = CourseManager::is_user_subscribed_in_course($userId, $courseCode);
2022
                    } else {
2023
                        $subscribe = CourseManager::is_user_subscribed_in_course(
2024
                            $userId,
2025
                            $courseCode,
2026
                            true,
2027
                            $sessionId
2028
                        );
2029
                    }
2030
2031
                    // User is not subscribe skip!
2032
                    if (empty($subscribe)) {
2033
                        continue;
2034
                    }
2035
                }
2036
2037
                $survey = $invitation->getSurvey();
2038
                if (null === $survey) {
2039
                    continue;
2040
                }
2041
2042
                $url = $mainUrl.'survey_id='.$survey->getIid().'&cid='.$courseId.'&sid='.$sessionId;
2043
                $title = $survey->getTitle();
2044
                $title = Display::url($title, $url);
2045
                $courseTitle = $course->getTitle();
2046
                if (!empty($sessionId)) {
2047
                    $courseTitle .= ' ('.$invitation->getSession()->getTitle().')';
2048
                }
2049
2050
                $surveyData = self::get_survey($survey->getIid(), 0, $courseCode);
2051
                $table->setCellContents($row, 0, $title);
2052
                $table->setCellContents($row, 1, $courseTitle);
2053
2054
                if (empty($answered)) {
2055
                    $table->setHeaderContents(
2056
                        $row,
2057
                        2,
2058
                        api_get_local_time(
2059
                            $survey->getAvailTill(),
2060
                            null,
2061
                            null,
2062
                            true,
2063
                            false
2064
                        )
2065
                    );
2066
                }
2067
2068
                if (!empty($answered) && 0 == $survey->getAnonymous()) {
2069
                    $answers = SurveyUtil::displayCompleteReport(
2070
                        $surveyData,
2071
                        $userId,
2072
                        false,
2073
                        false,
2074
                        false
2075
                    );
2076
                    $table->setCellContents(++$row, 0, $answers);
2077
                    $table->setCellContents(++$row, 1, '');
2078
                }
2079
2080
                $row++;
2081
            }
2082
            $content .= $table->toHtml();
2083
        } else {
2084
            $content .= Display::return_message(get_lang('No data available'));
2085
        }
2086
2087
        return $content;
2088
    }
2089
2090
    public static function sendToTutors(CSurvey $survey)
2091
    {
2092
        $surveyId = $survey->getIid();
2093
2094
        $extraFieldValue = new ExtraFieldValue('survey');
2095
        $groupData = $extraFieldValue->get_values_by_handler_and_field_variable($surveyId, 'group_id');
2096
        if ($groupData && !empty($groupData['value'])) {
2097
            $groupInfo = GroupManager::get_group_properties($groupData['value']);
2098
            if ($groupInfo) {
2099
                $tutors = GroupManager::getTutors($groupInfo);
2100
                if (!empty($tutors)) {
2101
                    SurveyUtil::saveInviteMail(
2102
                        $survey,
2103
                        ' ',
2104
                        ' ',
2105
                        false
2106
                    );
2107
2108
                    foreach ($tutors as $tutor) {
2109
                        $subject = sprintf(get_lang('Group survey for %s'), $groupInfo['name']);
2110
                        $content = sprintf(
2111
                            get_lang('Hi %s <br/><br/>As group tutor for the group %s you are invited to participate at the following survey :'),
2112
                            $tutor['complete_name'],
2113
                            $groupInfo['name']
2114
                        );
2115
2116
                        SurveyUtil::saveInvitations(
2117
                            $survey,
2118
                            ['users' => $tutor['user_id']],
2119
                            $subject,
2120
                            $content,
2121
                            false,
2122
                            true,
2123
                            false,
2124
                            true
2125
                        );
2126
                    }
2127
                    Display::addFlash(Display::return_message(get_lang('Updated'), 'confirmation', false));
2128
                }
2129
                SurveyUtil::updateInvitedCount($survey);
2130
2131
                return true;
2132
            }
2133
        }
2134
2135
        return false;
2136
    }
2137
2138
    public static function getInvitationsAnswered(
2139
        string $surveyCode,
2140
        int $courseId,
2141
        int $sessionId = 0
2142
    ): array {
2143
        $em = Database::getManager();
2144
2145
        $qb = $em->createQueryBuilder();
2146
        $qb->select('i')
2147
            ->from(CSurveyInvitation::class, 'i')
2148
            ->innerJoin('i.survey', 's')
2149
            ->andWhere('s.code = :code')
2150
            ->andWhere('IDENTITY(i.course) = :courseId')
2151
            ->andWhere('i.answered = 1')
2152
            ->setParameter('code', $surveyCode)
2153
            ->setParameter('courseId', $courseId)
2154
            ->orderBy('i.invitationDate', 'DESC');
2155
2156
        if ($sessionId > 0) {
2157
            $qb->andWhere('IDENTITY(i.session) = :sid')
2158
                ->setParameter('sid', (int) $sessionId);
2159
        } else {
2160
            $qb->andWhere(
2161
                $qb->expr()->orX(
2162
                    'i.session IS NULL',
2163
                    'IDENTITY(i.session) = 0'
2164
                )
2165
            );
2166
        }
2167
2168
        $query = $qb->getQuery();
2169
2170
        return $query->getResult();
2171
    }
2172
}
2173