Completed
Push — master ( 1a5e2c...34133a )
by Julito
08:10
created

survey_question::getJs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use ChamiloSession as Session;
6
7
/**
8
 * Class survey_question.
9
 */
10
class survey_question
11
{
12
    public $buttonList = [];
13
    /** @var FormValidator */
14
    private $form;
15
16
    /**
17
     * @param array $surveyData
18
     */
19
    public function addParentMenu($formData, FormValidator $form, $surveyData)
20
    {
21
        $surveyId = $surveyData['survey_id'];
22
        $questionId = isset($formData['question_id']) ? $formData['question_id'] : 0;
23
        $parentId = isset($formData['parent_id']) ? $formData['parent_id'] : 0;
24
        $optionId = isset($formData['parent_option_id']) ? $formData['parent_option_id'] : 0;
25
        $questions = SurveyManager::get_questions($surveyId);
26
27
        $newQuestionList = [];
28
        $allowTypes = ['yesno', 'multiplechoice'];
29
        foreach ($questions as $question) {
30
            if (in_array($question['type'], $allowTypes)) {
31
                $newQuestionList[$question['sort']] = $question;
32
            }
33
        }
34
        ksort($newQuestionList);
35
36
        $options = [];
37
        foreach ($newQuestionList as $question) {
38
            if (!empty($questionId)) {
39
                if ($question['question_id'] == $questionId) {
40
                    break;
41
                }
42
            }
43
            $options[$question['question_id']] = strip_tags($question['question']);
44
        }
45
        $form->addSelect(
46
            'parent_id',
47
            get_lang('Parent'),
48
            $options,
49
            ['id' => 'parent_id', 'placeholder' => get_lang('SelectAnOption')]
50
        );
51
        $url = api_get_path(WEB_AJAX_PATH).
52
            'survey.ajax.php?'.api_get_cidreq().'&a=load_question_options&survey_id='.$surveyId;
53
        $form->addHtml('
54
            <script>
55
                $(function() {                    
56
                    $("#parent_id").on("change", function() {
57
                        var questionId = $(this).val()
58
                        var $select = $("#parent_option_id");
59
                        $select.empty();
60
                            
61
                        if (questionId === "") {
62
                              $("#option_list").hide();
63
                        } else {
64
                            $.getJSON({
65
                                url: "'.$url.'" + "&question_id=" + questionId,
66
                            success: function(data) {
67
                                $("#parent_options").html(data);
68
                                    $.each(data, function(key, value) {
69
                                        $("<option>").val(key).text(value).appendTo($select);
70
                                    });
71
                            }
72
                        });        
73
                        }
74
                    });
75
                });
76
            </script>
77
        ');
78
79
        $style = 'display:none';
80
        $options = [];
81
        if (!empty($optionId) && !empty($parentId)) {
82
            $parentData = SurveyManager::get_question($parentId);
83
            $style = '';
84
            foreach ($parentData['answer_data'] as $answer) {
85
                $options[$answer['iid']] = strip_tags($answer['data']);
86
            }
87
        }
88
89
        $form->addHtml('<div id="option_list" style="'.$style.'">');
90
        $form->addSelect(
91
            'parent_option_id',
92
            get_lang('Option'),
93
            $options,
94
            ['id' => 'parent_option_id', 'disable_js' => true]
95
        );
96
        $form->addHtml('</div>');
97
    }
98
99
    /**
100
     * @param string $type
101
     *
102
     * @return survey_question
103
     */
104
    public static function createQuestion($type)
105
    {
106
        switch ($type) {
107
            case 'comment':
108
                return new ch_comment();
109
            case 'dropdown':
110
                return new ch_dropdown();
111
            case 'multiplechoice':
112
                return new ch_multiplechoice();
113
            case 'multipleresponse':
114
                return new ch_multipleresponse();
115
            case 'open':
116
                return new ch_open();
117
            case 'pagebreak':
118
                return new ch_pagebreak();
119
            case 'percentage':
120
                return new ch_percentage();
121
            case 'personality':
122
                return new ch_personality();
123
            case 'score':
124
                return new ch_score();
125
            case 'yesno':
126
                return new ch_yesno();
127
            case 'selectivedisplay':
128
                return new ch_selectivedisplay();
129
            case 'multiplechoiceother':
130
                return new ch_multiplechoiceother();
131
            default:
132
                api_not_allowed(true);
133
                break;
134
        }
135
    }
136
137
    /**
138
     * Generic part of any survey question: the question field.
139
     *
140
     * @param array $surveyData
141
     * @param array $formData
142
     *
143
     * @return FormValidator
144
     */
145
    public function createForm($surveyData, $formData)
146
    {
147
        $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : null;
148
        $questionId = isset($_GET['question_id']) ? (int) $_GET['question_id'] : null;
149
        $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : null;
150
        $type = isset($_GET['type']) ? Security::remove_XSS($_GET['type']) : null;
151
152
        $actionHeader = get_lang('EditQuestion').': ';
153
        if ($action === 'add') {
154
            $actionHeader = get_lang('AddQuestion').': ';
155
        }
156
157
        $questionComment = '';
158
        $allowParent = false;
159
        switch ($type) {
160
            case 'open':
161
                $toolName = get_lang('Open');
162
                $questionComment = get_lang('QuestionTags');
163
                $allowParent = true;
164
                break;
165
            case 'yesno':
166
                $toolName = get_lang('YesNo');
167
                $allowParent = true;
168
                break;
169
            case 'multiplechoice':
170
                $toolName = get_lang('UniqueSelect');
171
                $allowParent = true;
172
                break;
173
            case 'multipleresponse':
174
                $toolName = get_lang('MultipleResponse');
175
                $allowParent = true;
176
                break;
177
            case 'selectivedisplay':
178
                $toolName = get_lang('SurveyQuestionSelectiveDisplay');
179
                $questionComment = get_lang('SurveyQuestionSelectiveDisplayComment');
180
                $allowParent = true;
181
                break;
182
            case 'multiplechoiceother':
183
                $toolName = get_lang('SurveyMultipleAnswerWithOther');
184
                $allowParent = true;
185
                break;
186
            case 'pagebreak':
187
                $toolName = get_lang(api_ucfirst($type));
188
                $allowParent = false;
189
                break;
190
            default:
191
                $toolName = get_lang(api_ucfirst($type));
192
                $allowParent = true;
193
                break;
194
        }
195
196
        if (false === api_get_configuration_value('survey_question_dependency')) {
197
            $allowParent = false;
198
        }
199
200
        $icon = Display::return_icon(
201
                SurveyManager::icon_question($type),
202
                $toolName,
203
                ['align' => 'middle', 'height' => '22px']
204
            ).' ';
205
206
        $toolName = $icon.$actionHeader.$toolName;
207
        $sharedQuestionId = isset($formData['shared_question_id']) ? $formData['shared_question_id'] : null;
208
209
        $url = api_get_self().'?action='.$action.'&type='.$type.'&survey_id='.$surveyId.'&question_id='.$questionId.'&'.api_get_cidreq();
210
        $form = new FormValidator('question_form', 'post', $url);
211
        $form->addHeader($toolName);
212
        if (!empty($questionComment)) {
213
            $form->addHtml(Display::return_message($questionComment, 'info', false));
214
        }
215
        $form->addHidden('survey_id', $surveyId);
216
        $form->addHidden('question_id', $questionId);
217
        $form->addHidden('shared_question_id', Security::remove_XSS($sharedQuestionId));
218
        $form->addHidden('type', $type);
219
220
        $config = [
221
            'ToolbarSet' => 'SurveyQuestion',
222
            'Width' => '100%',
223
            'Height' => '120',
224
        ];
225
        $form->addHtmlEditor(
226
            'question',
227
            get_lang('Question'),
228
            true,
229
            false,
230
            $config
231
        );
232
233
        if (api_get_configuration_value('allow_required_survey_questions') &&
234
            in_array($_GET['type'], ['yesno', 'multiplechoice'])) {
235
            $form->addCheckBox('is_required', get_lang('Mandatory?'), get_lang('Yes'));
236
        }
237
238
        if ($allowParent) {
239
            $this->addParentMenu($formData, $form, $surveyData);
240
        }
241
        // When survey type = 1??
242
        if (1 == $surveyData['survey_type']) {
243
            $table_survey_question_group = Database::get_course_table(TABLE_SURVEY_QUESTION_GROUP);
244
            $sql = 'SELECT id,name FROM '.$table_survey_question_group.'
245
                    WHERE survey_id = '.$surveyId.'
246
                    ORDER BY name';
247
            $rs = Database::query($sql);
248
            $glist = null;
249
            while ($row = Database::fetch_array($rs, 'NUM')) {
250
                $glist .= '<option value="'.$row[0].'" >'.$row[1].'</option>';
251
            }
252
253
            $grouplist = $grouplist1 = $grouplist2 = $glist;
254
            if (!empty($formData['assigned'])) {
255
                $grouplist = str_replace(
256
                    '<option value="'.$formData['assigned'].'"',
257
                    '<option value="'.$formData['assigned'].'" selected',
258
                    $glist
259
                );
260
            }
261
262
            if (!empty($formData['assigned1'])) {
263
                $grouplist1 = str_replace(
264
                    '<option value="'.$formData['assigned1'].'"',
265
                    '<option value="'.$formData['assigned1'].'" selected',
266
                    $glist
267
                );
268
            }
269
270
            if (!empty($formData['assigned2'])) {
271
                $grouplist2 = str_replace(
272
                    '<option value="'.$formData['assigned2'].'"',
273
                    '<option value="'.$formData['assigned2'].'" selected',
274
                    $glist
275
                );
276
            }
277
278
            $this->html .= '	<tr><td colspan="">
0 ignored issues
show
Bug Best Practice introduced by
The property html does not exist on survey_question. Did you maybe forget to declare it?
Loading history...
279
			<fieldset style="border:1px solid black"><legend>'.get_lang('Condition').'</legend>
280
281
			<b>'.get_lang('Primary').'</b><br />
282
			'.'<input type="radio" name="choose" value="1" '.((1 == $formData['choose']) ? 'checked' : '').
283
                '><select name="assigned">'.$grouplist.'</select><br />';
284
285
            $this->html .= '
286
			<b>'.get_lang('Secondary').'</b><br />
287
			'.'<input type="radio" name="choose" value="2" '.((2 == $formData['choose']) ? 'checked' : '').
288
                '><select name="assigned1">'.$grouplist1.'</select> '.
289
                '<select name="assigned2">'.$grouplist2.'</select>'
290
                .'</fieldset><br />';
291
        }
292
293
        $this->setForm($form);
294
295
        return $form;
296
    }
297
298
    /**
299
     * Adds submit button.
300
     */
301
    public function renderForm()
302
    {
303
        if (isset($_GET['question_id']) && !empty($_GET['question_id'])) {
304
            /**
305
             * Check if survey has answers first before update it, this is because if you update it, the question
306
             * options will delete and re-insert in database loosing the iid and question_id to verify the correct answers.
307
             */
308
            $surveyId = isset($_GET['survey_id']) ? (int) $_GET['survey_id'] : 0;
309
            $answersChecker = SurveyUtil::checkIfSurveyHasAnswers($surveyId);
310
            if (!$answersChecker) {
311
                $this->buttonList[] = $this->getForm()->addButtonUpdate(get_lang('Edit question'), 'save', true);
312
            } else {
313
                $this->getForm()->addHtml('
314
                    <div class="form-group">
315
                        <label class="col-sm-2 control-label"></label>
316
                        <div class="col-sm-8">
317
                            <div class="alert alert-info">'.get_lang('You can\'t edit this question because answers by students have already been registered').'</div>
318
                        </div>
319
                        <div class="col-sm-2"></div>
320
                    </div>
321
                ');
322
            }
323
        } else {
324
            $this->buttonList[] = $this->getForm()->addButtonSave(get_lang('Create question'), 'save', true);
325
        }
326
327
        $this->getForm()->addGroup($this->buttonList, 'buttons');
328
    }
329
330
    /**
331
     * @return FormValidator
332
     */
333
    public function getForm()
334
    {
335
        return $this->form;
336
    }
337
338
    /**
339
     * @param FormValidator $form
340
     */
341
    public function setForm($form)
342
    {
343
        $this->form = $form;
344
    }
345
346
    /**
347
     * @param array $formData
348
     *
349
     * @return mixed
350
     */
351
    public function preSave($formData)
352
    {
353
        $counter = Session::read('answer_count');
354
        $answerList = Session::read('answer_list');
355
356
        if (empty($answerList)) {
357
            $answerList = isset($formData['answers']) ? $formData['answers'] : [];
358
            Session::write('answer_list', $answerList);
359
        }
360
361
        if (isset($_POST['answers'])) {
362
            $formData['answers'] = $_POST['answers'];
363
        }
364
365
        if (empty($counter)) {
366
            $counter = count($answerList) - 1;
367
            Session::write('answer_count', $counter);
368
        }
369
370
        // Moving an answer up
371
        if (isset($_POST['move_up']) && $_POST['move_up']) {
372
            foreach ($_POST['move_up'] as $key => &$value) {
373
                $id1 = $key;
374
                $content1 = $formData['answers'][$id1];
375
                $id2 = $key - 1;
376
                $content2 = $formData['answers'][$id2];
377
                $formData['answers'][$id1] = $content2;
378
                $formData['answers'][$id2] = $content1;
379
            }
380
        }
381
382
        // Moving an answer down
383
        if (isset($_POST['move_down']) && $_POST['move_down']) {
384
            foreach ($_POST['move_down'] as $key => &$value) {
385
                $id1 = $key;
386
                $content1 = $formData['answers'][$id1];
387
                $id2 = $key + 1;
388
                $content2 = $formData['answers'][$id2];
389
                $formData['answers'][$id1] = $content2;
390
                $formData['answers'][$id2] = $content1;
391
            }
392
        }
393
394
        /**
395
         * Deleting a specific answer is only saved in the session until the
396
         * "Save question" button is pressed. This means all options are kept
397
         * in the survey_question_option table until the question is saved.
398
         */
399
        if (isset($_POST['delete_answer'])) {
400
            $deleted = false;
401
            foreach ($_POST['delete_answer'] as $key => &$value) {
402
                $deleted = $key;
403
                $counter--;
404
                Session::write('answer_count', $counter);
405
            }
406
407
            $newAnswers = [];
408
            $newAnswersId = [];
409
            foreach ($formData['answers'] as $key => &$value) {
410
                if ($key > $deleted) {
411
                    // swap with previous (deleted) option slot
412
                    $newAnswers[$key - 1] = $formData['answers'][$key];
413
                    $newAnswersId[$key - 1] = $formData['answersid'][$key];
414
                    unset($formData['answers'][$key]);
415
                    unset($formData['answersid'][$key]);
416
                } elseif ($key === $deleted) {
417
                    // delete option
418
                    unset($formData['answers'][$deleted]);
419
                    unset($formData['answersid'][$deleted]);
420
                } else {
421
                    // keep as is
422
                    $newAnswers[$key] = $value;
423
                    $newAnswersId[$key] = $formData['answersid'][$key];
424
                }
425
            }
426
            unset($formData['answers']);
427
            unset($formData['answersid']);
428
            $formData['answers'] = $newAnswers;
429
            $formData['answersid'] = $newAnswersId;
430
        }
431
432
        // Adding an answer
433
        if (isset($_POST['buttons']) && isset($_POST['buttons']['add_answer'])) {
434
            if (isset($_REQUEST['type']) && 'multiplechoiceother' === $_REQUEST['type']) {
435
                $counter--;
436
            }
437
            $counter++;
438
            Session::write('answer_count', $counter);
439
        }
440
441
        // Removing an answer
442
        if (isset($_POST['buttons']) && isset($_POST['buttons']['remove_answer'])) {
443
            $counter--;
444
            Session::write('answer_count', $counter);
445
            foreach ($formData['answers'] as $index => &$data) {
446
                if ($index > $counter) {
447
                    unset($formData['answers'][$index]);
448
                    unset($formData['answersid'][$index]);
449
                }
450
            }
451
        }
452
453
        if (!isset($_POST['delete_answer'])) {
454
            // Make sure we have an array of answers
455
            if (!isset($formData['answers'])) {
456
                $formData['answers'] = [];
457
            }
458
            // Check if no deleted answer remains at the end of the answers
459
            // array and add empty answers if the array is too short
460
                foreach ($formData['answers'] as $index => $data) {
461
                    if ($index > $counter) {
462
                        unset($formData['answers'][$index]);
463
                    }
464
                }
465
466
                for ($i = 0; $i <= $counter; $i++) {
467
                    if (!isset($formData['answers'][$i])) {
468
                        $formData['answers'][$i] = '';
469
                }
470
            }
471
        }
472
473
        $formData['answers'] = isset($formData['answers']) ? $formData['answers'] : [];
474
        Session::write('answer_list', $formData['answers']);
475
476
        if (!isset($formData['is_required']) && api_get_configuration_value('survey_mark_question_as_required')) {
477
            $formData['is_required'] = true;
478
        }
479
480
        return $formData;
481
    }
482
483
    /**
484
     * @param array $surveyData
485
     * @param array $formData
486
     *
487
     * @return mixed
488
     */
489
    public function save($surveyData, $formData)
490
    {
491
        // Saving a question
492
        if (isset($_POST['buttons']) && isset($_POST['buttons']['save'])) {
493
            Session::erase('answer_count');
494
            Session::erase('answer_list');
495
            $message = SurveyManager::save_question($surveyData, $formData, true, $dataFromDatabase);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dataFromDatabase seems to be never defined.
Loading history...
496
497
            if ($message === 'QuestionAdded' || $message === 'QuestionUpdated') {
498
                $url = api_get_path(WEB_CODE_PATH).'survey/survey.php?survey_id='.intval($_GET['survey_id']).'&message='.$message.'&'.api_get_cidreq();
499
                header('Location: '.$url);
500
                exit;
501
            }
502
        }
503
504
        return $formData;
505
    }
506
507
    /**
508
     * Adds two buttons. One to add an option, one to remove an option.
509
     *
510
     * @param array $data
511
     */
512
    public function addRemoveButtons($data)
513
    {
514
        $this->buttonList['remove_answer'] = $this->getForm()->createElement(
515
            'button',
516
            'remove_answer',
517
            get_lang('Remove option'),
518
            'minus',
519
            'default'
520
        );
521
522
        if (count($data['answers']) <= 2) {
523
            $this->buttonList['remove_answer']->updateAttributes(
524
                ['disabled' => 'disabled']
525
            );
526
        }
527
528
        $this->buttonList['add_answer'] = $this->getForm()->createElement(
529
            'button',
530
            'add_answer',
531
            get_lang('Add option'),
532
            'plus',
533
            'default'
534
        );
535
    }
536
537
    /**
538
     * Get the JS for questions that can depend on a previous question
539
     * (and that hides those questions until something changes in the previous
540
     * question).
541
     *
542
     * @return string HTML code
543
     */
544
    public static function getJs()
545
    {
546
        return '
547
            <style>
548
            .with_parent {
549
                display: none;
550
            }
551
            </style>
552
            <script>
553
            $(function() {
554
            });
555
            </script>';
556
    }
557
558
    /**
559
     * Get the question parents recursively, if any. This function depends on
560
     * the existence of a parent_id field, which depends on the
561
     * 'survey_question_dependency' setting and its corresponding SQL
562
     * requirements.
563
     *
564
     * @param int   $questionId The c_survey_question.question.id
565
     * @param array $list       An array of parents to be extended by this method
566
     *
567
     * @return array The completed array of parents
568
     */
569
    public static function getParents($questionId, $list = [])
570
    {
571
        if (true !== api_get_configuration_value('survey_question_dependency')) {
572
            return $list;
573
        }
574
        $courseId = api_get_course_int_id();
575
        $questionId = (int) $questionId;
576
577
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
578
        $sql = "SELECT parent_id FROM $table
579
                WHERE c_id = $courseId AND question_id = $questionId ";
580
        $result = Database::query($sql);
581
        $row = Database::fetch_array($result, 'ASSOC');
582
        if ($row && !empty($row['parent_id'])) {
583
            $list[] = $row['parent_id'];
584
            $list = self::getParents($row['parent_id'], $list);
585
        }
586
587
        return $list;
588
    }
589
590
    /**
591
     * Creates the JS code for the given parent question so that it shows
592
     * the children questions when a specific answer of the parent is selected.
593
     *
594
     * @param array $question An array with the question details
595
     *
596
     * @return string JS code to add to the HTML survey question page
597
     */
598
    public static function getQuestionJs($question)
599
    {
600
        $list = self::getDependency($question);
601
        if (empty($list)) {
602
            return '';
603
        }
604
605
        $js = '';
606
        $questionId = $question['question_id'];
607
        $newList = [];
608
        foreach ($list as $child) {
609
            $childQuestionId = $child['question_id'];
610
            $optionId = $child['parent_option_id'];
611
            $newList[$optionId] = $childQuestionId;
612
        }
613
614
        $js .= '
615
            <script>
616
            $(function() {
617
                var list = '.json_encode($newList).';
618
                $("input[name=question'.$questionId.']").on("click", function() {
619
                    $.each(list, function(index, value) {
620
                        $(".with_parent_" + value).hide();
621
                        $(".with_parent_" + value).find("input").prop("checked", false);
622
                        $(".with_parent_only_hide_" + value).hide();
623
                    });
624
625
                    var questionId = $(this).val();
626
                    var questionToShow = list[questionId];
627
                    $(".with_parent_" + questionToShow).show();
628
                });
629
            });
630
            </script>';
631
632
        return $js;
633
    }
634
635
    /**
636
     * Returns the (children) questions that have the given question as parent.
637
     *
638
     * @param array $question An array describing the parent question
639
     *
640
     * @return array The questions that have the given question as parent
641
     */
642
    public static function getDependency($question)
643
    {
644
        if (true !== api_get_configuration_value('survey_question_dependency')) {
645
            return [];
646
        }
647
        $table = Database::get_course_table(TABLE_SURVEY_QUESTION);
648
        $questionId = $question['question_id'];
649
        $courseId = api_get_course_int_id();
650
651
        // Getting the information of the question
652
        $sql = "SELECT * FROM $table
653
		        WHERE c_id = $courseId AND parent_id = $questionId ";
654
        $result = Database::query($sql);
655
        $row = Database::store_result($result, 'ASSOC');
656
657
        return $row;
658
    }
659
660
    /**
661
     * This method is not implemented at this level (returns null).
662
     *
663
     * @param array $questionData
664
     * @param array $answers
665
     */
666
    public function render(FormValidator $form, $questionData = [], $answers = [])
0 ignored issues
show
Unused Code introduced by
The parameter $questionData is not used and could be removed. ( Ignorable by Annotation )

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

666
    public function render(FormValidator $form, /** @scrutinizer ignore-unused */ $questionData = [], $answers = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $answers is not used and could be removed. ( Ignorable by Annotation )

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

666
    public function render(FormValidator $form, $questionData = [], /** @scrutinizer ignore-unused */ $answers = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
667
    {
668
        return null;
669
    }
670
}
671