Answer::updateAnswers()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 16
nc 2
nop 9
dl 0
loc 33
rs 9.7333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CourseBundle\Entity\CQuizAnswer;
6
7
/**
8
 * Class Answer
9
 * Allows to instantiate an object of type Answer, as a *list* of answers for one question
10
 * 5 arrays are created to receive the attributes of each answer belonging to a specified question.
11
 *
12
 * @author Olivier Brouckaert
13
 */
14
class Answer
15
{
16
    /* The question of which we want the possible answers */
17
    public $questionId;
18
19
    // these are arrays
20
    public $answer;
21
    public $correct;
22
    public $comment;
23
    public $weighting;
24
    public $position;
25
    public $hotspot_coordinates;
26
    public $hotspot_type;
27
    public $destination;
28
    // these arrays are used to save temporarily new answers
29
    // then they are moved into the arrays above or deleted in the event of cancellation
30
    public $new_answer;
31
    public $new_correct;
32
    public $new_comment;
33
    public $new_weighting;
34
    public $new_position;
35
    public $new_hotspot_coordinates;
36
    public $new_hotspot_type;
37
    /** @var int Incremental ID used in the past when PK was a mix of c_id+id */
38
    public $autoId;
39
    /** @var int Number of answers in the question */
40
    public $nbrAnswers;
41
    public $new_nbrAnswers;
42
    public $new_destination; // id of the next question if feedback option is set to Directfeedback
43
    public $course; //Course information
44
    public $iid;
45
    public $questionJSId;
46
    public $standalone;
47
    /** @var Exercise|null */
48
    private $exercise;
49
50
    /**
51
     * @author Olivier Brouckaert
52
     *
53
     * @param int      $questionId that answers belong to
54
     * @param int      $course_id
55
     * @param Exercise $exercise
56
     * @param bool     $readAnswer
57
     */
58
    public function __construct($questionId, $course_id = 0, $exercise = null, $readAnswer = true)
59
    {
60
        $this->questionId = (int) $questionId;
61
        $this->answer = [];
62
        $this->correct = [];
63
        $this->comment = [];
64
        $this->weighting = [];
65
        $this->position = [];
66
        $this->hotspot_coordinates = [];
67
        $this->hotspot_type = [];
68
        $this->destination = [];
69
        // clears $new_* arrays
70
        $this->cancel();
71
72
        if (!empty($course_id)) {
73
            $courseInfo = api_get_course_info_by_id($course_id);
74
        } else {
75
            $courseInfo = api_get_course_info();
76
        }
77
78
        $this->course = $courseInfo;
79
        $this->course_id = $courseInfo['real_id'];
80
81
        if (empty($exercise)) {
82
            // fills arrays
83
            $objExercise = new Exercise($this->course_id);
84
            $exerciseId = isset($_REQUEST['exerciseId']) ? $_REQUEST['exerciseId'] : null;
85
            $objExercise->read($exerciseId, false);
86
        } else {
87
            $objExercise = $exercise;
88
        }
89
        $this->exercise = $objExercise;
90
91
        if ($readAnswer) {
92
            if ($objExercise->random_answers == '1' && $this->getQuestionType() != CALCULATED_ANSWER) {
93
                $this->readOrderedBy('rand()', ''); // randomize answers
94
            } else {
95
                $this->read(); // natural order
96
            }
97
        }
98
    }
99
100
    /**
101
     * Clears $new_* arrays.
102
     *
103
     * @author Olivier Brouckaert
104
     */
105
    public function cancel()
106
    {
107
        $this->new_answer = [];
108
        $this->new_correct = [];
109
        $this->new_comment = [];
110
        $this->new_weighting = [];
111
        $this->new_position = [];
112
        $this->new_hotspot_coordinates = [];
113
        $this->new_hotspot_type = [];
114
        $this->new_nbrAnswers = 0;
115
        $this->new_destination = [];
116
    }
117
118
    /**
119
     * Reads answer information from the database.
120
     *
121
     * @author Olivier Brouckaert
122
     */
123
    public function read()
124
    {
125
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
126
        $questionId = $this->questionId;
127
128
        $sql = "SELECT * FROM $table
129
                WHERE question_id = $questionId
130
                ORDER BY position";
131
132
        $result = Database::query($sql);
133
        $i = 1;
134
135
        // while a record is found
136
        while ($object = Database::fetch_object($result)) {
137
            $this->id[$i] = $object->iid;
138
            $this->iid[$i] = $object->iid;
139
            $this->answer[$i] = $object->answer;
140
            $this->correct[$i] = $object->correct;
141
            $this->comment[$i] = $object->comment;
142
            $this->weighting[$i] = $object->ponderation;
143
            $this->position[$i] = $object->position;
144
            $this->hotspot_coordinates[$i] = $object->hotspot_coordinates;
145
            $this->hotspot_type[$i] = $object->hotspot_type;
146
            $this->destination[$i] = $object->destination;
147
            $this->autoId[$i] = $object->id_auto;
148
            $i++;
149
        }
150
        $this->nbrAnswers = $i - 1;
151
    }
152
153
    /**
154
     * Get answers already added to question.
155
     *
156
     * @return array
157
     */
158
    public function getAnswers()
159
    {
160
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
161
        $questionId = $this->questionId;
162
163
        $sql = "SELECT * FROM $table
164
                WHERE question_id = $questionId
165
                ORDER BY position";
166
167
        $result = Database::query($sql);
168
169
        $answers = [];
170
171
        // while a record is found
172
        while ($answer = Database::fetch_assoc($result)) {
173
            $answers[] = $answer;
174
        }
175
176
        return $answers;
177
    }
178
179
    /**
180
     * @param int $id
181
     *
182
     * @return array
183
     */
184
    public function getAnswerByAutoId($id)
185
    {
186
        foreach ($this->autoId as $key => $autoId) {
187
            if ($autoId == $id) {
188
                return [
189
                    'answer' => $this->answer[$key],
190
                    'correct' => $this->correct[$key],
191
                    'comment' => $this->comment[$key],
192
                ];
193
            }
194
        }
195
196
        return [];
197
    }
198
199
    /**
200
     * returns all answer ids from this question Id.
201
     *
202
     * @author Yoselyn Castillo
203
     *
204
     * @return array - $id (answer ids)
205
     */
206
    public function selectAnswerId()
207
    {
208
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
209
        $questionId = $this->questionId;
210
211
        $sql = "SELECT iid FROM $table WHERE question_id = $questionId";
212
213
        $result = Database::query($sql);
214
        $id = [];
215
        // while a record is found
216
        if (Database::num_rows($result) > 0) {
217
            while ($object = Database::fetch_array($result)) {
218
                $id[] = $object['iid'];
219
            }
220
        }
221
222
        return $id;
223
    }
224
225
    /**
226
     * Reads answer information from the data base ordered by parameter.
227
     *
228
     * @param string $field Field we want to order by
229
     * @param string $order DESC or ASC
230
     *
231
     * @return bool
232
     *
233
     * @author Frederic Vauthier
234
     */
235
    public function readOrderedBy($field, $order = 'ASC')
236
    {
237
        $field = Database::escape_string($field);
238
        if (empty($field)) {
239
            $field = 'position';
240
        }
241
242
        if ('ASC' != $order && 'DESC' != $order) {
243
            $order = 'ASC';
244
        }
245
246
        $TBL_ANSWER = Database::get_course_table(TABLE_QUIZ_ANSWER);
247
        $TBL_QUESTION = Database::get_course_table(TABLE_QUIZ_QUESTION);
248
        $questionId = (int) $this->questionId;
249
250
        $sql = "SELECT type FROM $TBL_QUESTION WHERE iid = $questionId";
251
        $result_question = Database::query($sql);
252
        $questionType = Database::fetch_array($result_question);
253
254
        if (DRAGGABLE == $questionType['type']) {
255
            // Random is done by submit.js.tpl
256
            $this->read();
257
258
            return true;
259
        }
260
261
        $sql = "SELECT
262
                    answer,
263
                    correct,
264
                    comment,
265
                    ponderation,
266
                    position,
267
                    hotspot_coordinates,
268
                    hotspot_type,
269
                    destination,
270
                    id_auto,
271
                    iid
272
                FROM $TBL_ANSWER
273
                WHERE
274
                    question_id='".$questionId."'
275
                ORDER BY $field $order";
276
        $result = Database::query($sql);
277
278
        $i = 1;
279
        // while a record is found
280
        $doubt_data = null;
281
        while ($object = Database::fetch_object($result)) {
282
            if ($questionType['type'] == UNIQUE_ANSWER_NO_OPTION && $object->position == 666) {
283
                $doubt_data = $object;
284
                continue;
285
            }
286
            $this->answer[$i] = $object->answer;
287
            $this->correct[$i] = $object->correct;
288
            $this->comment[$i] = $object->comment;
289
            $this->weighting[$i] = $object->ponderation;
290
            $this->position[$i] = $object->position;
291
            $this->hotspot_coordinates[$i] = $object->hotspot_coordinates;
292
            $this->hotspot_type[$i] = $object->hotspot_type;
293
            $this->destination[$i] = $object->destination;
294
            $this->autoId[$i] = $object->id_auto;
295
            $this->iid[$i] = $object->iid;
296
            $i++;
297
        }
298
299
        if ($questionType['type'] == UNIQUE_ANSWER_NO_OPTION && !empty($doubt_data)) {
300
            $this->answer[$i] = $doubt_data->answer;
301
            $this->correct[$i] = $doubt_data->correct;
302
            $this->comment[$i] = $doubt_data->comment;
303
            $this->weighting[$i] = $doubt_data->ponderation;
304
            $this->position[$i] = $doubt_data->position;
305
            $this->hotspot_coordinates[$i] = isset($object->hotspot_coordinates) ? $object->hotspot_coordinates : 0;
306
            $this->hotspot_type[$i] = isset($object->hotspot_type) ? $object->hotspot_type : 0;
307
            $this->destination[$i] = $doubt_data->destination;
308
            $this->autoId[$i] = $doubt_data->id_auto;
309
            $this->iid[$i] = $doubt_data->iid;
310
            $i++;
311
        }
312
        $this->nbrAnswers = $i - 1;
313
314
        return true;
315
    }
316
317
    /**
318
     * returns the autoincrement id.
319
     *
320
     * @author Juan Carlos Ra�a
321
     *
322
     * @return int Answer num
323
     */
324
    public function selectAutoId($id)
325
    {
326
        return isset($this->autoId[$id]) ? $this->autoId[$id] : 0;
327
    }
328
329
    /**
330
     * Returns the unique ID (iid field).
331
     *
332
     * @return int Answer ID
333
     */
334
    public function selectId($id)
335
    {
336
        return isset($this->iid[$id]) ? $this->iid[$id] : 0;
337
    }
338
339
    /**
340
     * returns the number of answers in this question.
341
     *
342
     * @author Olivier Brouckaert
343
     *
344
     * @return int - number of answers
345
     */
346
    public function selectNbrAnswers()
347
    {
348
        return $this->nbrAnswers;
349
    }
350
351
    /**
352
     * returns the question ID which the answers belong to.
353
     *
354
     * @author Olivier Brouckaert
355
     *
356
     * @return int - the question ID
357
     */
358
    public function selectQuestionId()
359
    {
360
        return $this->questionId;
361
    }
362
363
    /**
364
     * returns the question ID of the destination question.
365
     *
366
     * @author Julio Montoya
367
     *
368
     * @param int $id
369
     *
370
     * @return int - the question ID
371
     */
372
    public function selectDestination($id)
373
    {
374
        return isset($this->destination[$id]) ? $this->destination[$id] : null;
375
    }
376
377
    /**
378
     * returns the answer title.
379
     *
380
     * @author Olivier Brouckaert
381
     *
382
     * @param - integer $id - answer ID
383
     *
384
     * @return string - answer title
385
     */
386
    public function selectAnswer($id)
387
    {
388
        return isset($this->answer[$id]) ? $this->answer[$id] : null;
389
    }
390
391
    /**
392
     * return array answer by id else return a bool.
393
     *
394
     * @param int $auto_id
395
     *
396
     * @return array
397
     *
398
     * @todo Replace method by iid search
399
     */
400
    public function selectAnswerByAutoId($auto_id)
401
    {
402
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
403
        $auto_id = (int) $auto_id;
404
        $sql = "SELECT iid, answer FROM $table
405
                WHERE c_id = {$this->course_id} AND id_auto = $auto_id";
406
        $rs = Database::query($sql);
407
408
        if (Database::num_rows($rs) > 0) {
409
            return Database::fetch_array($rs, 'ASSOC');
410
        }
411
412
        return false;
413
    }
414
415
    /**
416
     * return array answer by iid. Else return a bool.
417
     *
418
     * @param int $iid
419
     *
420
     * @return array
421
     */
422
    public function selectAnswerById($id)
423
    {
424
        if (empty($id)) {
425
            return false;
426
        }
427
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
428
        $id = (int) $id;
429
        $sql = "SELECT iid, answer, id_auto FROM $table
430
                WHERE iid = $id";
431
        $rs = Database::query($sql);
432
433
        if (Database::num_rows($rs) > 0) {
434
            return Database::fetch_array($rs, 'ASSOC');
435
        }
436
437
        return false;
438
    }
439
440
    /**
441
     * returns the answer title from an answer's position.
442
     *
443
     * @author Yannick Warnier
444
     *
445
     * @param - integer $pos - answer ID
446
     *
447
     * @return bool - answer title
448
     */
449
    public function selectAnswerIdByPosition($pos)
450
    {
451
        foreach ($this->position as $k => $v) {
452
            if ($v != $pos) {
453
                continue;
454
            }
455
456
            return $k;
457
        }
458
459
        return false;
460
    }
461
462
    /**
463
     * Returns a list of answers.
464
     *
465
     * @author Yannick Warnier <[email protected]>
466
     *
467
     * @param bool $decode
468
     *
469
     * @return array List of answers where each answer is an array
470
     *               of (id, answer, comment, grade) and grade=weighting
471
     */
472
    public function getAnswersList($decode = false)
473
    {
474
        $list = [];
475
        for ($i = 1; $i <= $this->nbrAnswers; $i++) {
476
            if (!empty($this->answer[$i])) {
477
                //Avoid problems when parsing elements with accents
478
                if ($decode) {
479
                    $this->answer[$i] = api_html_entity_decode(
480
                        $this->answer[$i],
481
                        ENT_QUOTES,
482
                        api_get_system_encoding()
483
                    );
484
                    $this->comment[$i] = api_html_entity_decode(
485
                        $this->comment[$i],
486
                        ENT_QUOTES,
487
                        api_get_system_encoding()
488
                    );
489
                }
490
491
                $list[] = [
492
                    'iid' => $i,
493
                    'answer' => $this->answer[$i],
494
                    'comment' => $this->comment[$i],
495
                    'grade' => $this->weighting[$i],
496
                    'hotspot_coord' => $this->hotspot_coordinates[$i],
497
                    'hotspot_type' => $this->hotspot_type[$i],
498
                    'correct' => $this->correct[$i],
499
                    'destination' => $this->destination[$i],
500
                ];
501
            }
502
        }
503
504
        return $list;
505
    }
506
507
    /**
508
     * Returns a list of grades.
509
     *
510
     * @author Yannick Warnier <[email protected]>
511
     *
512
     * @return array List of grades where grade=weighting (?)
513
     */
514
    public function getGradesList()
515
    {
516
        $list = [];
517
        for ($i = 0; $i < $this->nbrAnswers; $i++) {
518
            if (!empty($this->answer[$i])) {
519
                $list[$i] = $this->weighting[$i];
520
            }
521
        }
522
523
        return $list;
524
    }
525
526
    /**
527
     * Returns the question type.
528
     *
529
     * @author    Yannick Warnier <[email protected]>
530
     *
531
     * @return int The type of the question this answer is bound to
532
     */
533
    public function getQuestionType()
534
    {
535
        $table = Database::get_course_table(TABLE_QUIZ_QUESTION);
536
        $sql = "SELECT type FROM $table
537
                WHERE iid = {$this->questionId}";
538
        $res = Database::query($sql);
539
        if (Database::num_rows($res) <= 0) {
540
            return null;
541
        }
542
        $row = Database::fetch_array($res);
543
544
        return (int) $row['type'];
545
    }
546
547
    /**
548
     * tells if answer is correct or not.
549
     *
550
     * @author Olivier Brouckaert
551
     *
552
     * @param - integer $id - answer ID
553
     *
554
     * @return int - 0 if bad answer, not 0 if good answer
555
     */
556
    public function isCorrect($id)
557
    {
558
        return isset($this->correct[$id]) ? $this->correct[$id] : null;
559
    }
560
561
    /**
562
     * returns answer comment.
563
     *
564
     * @author Olivier Brouckaert
565
     *
566
     * @param - integer $id - answer ID
567
     *
568
     * @return string - answer comment
569
     */
570
    public function selectComment($id)
571
    {
572
        return isset($this->comment[$id]) ? $this->comment[$id] : null;
573
    }
574
575
    /**
576
     * returns answer weighting.
577
     *
578
     * @author Olivier Brouckaert
579
     *
580
     * @param - integer $id - answer ID
581
     *
582
     * @return int - answer weighting
583
     */
584
    public function selectWeighting($id)
585
    {
586
        return isset($this->weighting[$id]) ? $this->weighting[$id] : null;
587
    }
588
589
    /**
590
     * returns answer position.
591
     *
592
     * @author Olivier Brouckaert
593
     *
594
     * @param - integer $id - answer ID
595
     *
596
     * @return int - answer position
597
     */
598
    public function selectPosition($id)
599
    {
600
        return isset($this->position[$id]) ? $this->position[$id] : null;
601
    }
602
603
    /**
604
     * returns answer hotspot coordinates.
605
     *
606
     * @author Olivier Brouckaert
607
     *
608
     * @param int $id Answer ID
609
     *
610
     * @return int Answer position
611
     */
612
    public function selectHotspotCoordinates($id)
613
    {
614
        return isset($this->hotspot_coordinates[$id]) ? $this->hotspot_coordinates[$id] : null;
615
    }
616
617
    /**
618
     * returns answer hotspot type.
619
     *
620
     * @author Toon Keppens
621
     *
622
     * @param int $id Answer ID
623
     *
624
     * @return int Answer position
625
     */
626
    public function selectHotspotType($id)
627
    {
628
        return isset($this->hotspot_type[$id]) ? $this->hotspot_type[$id] : null;
629
    }
630
631
    /**
632
     * Creates a new answer.
633
     *
634
     * @author Olivier Brouckaert
635
     *
636
     * @param string $answer                  answer title
637
     * @param int    $correct                 0 if bad answer, not 0 if good answer
638
     * @param string $comment                 answer comment
639
     * @param int    $weighting               answer weighting
640
     * @param int    $position                answer position
641
     * @param array  $new_hotspot_coordinates Coordinates for hotspot exercises (optional)
642
     * @param int    $new_hotspot_type        Type for hotspot exercises (optional)
643
     * @param string $destination
644
     */
645
    public function createAnswer(
646
        $answer,
647
        $correct,
648
        $comment,
649
        $weighting,
650
        $position,
651
        $new_hotspot_coordinates = null,
652
        $new_hotspot_type = null,
653
        $destination = ''
654
    ) {
655
        $this->new_nbrAnswers++;
656
        $id = $this->new_nbrAnswers;
657
        $this->new_answer[$id] = $answer;
658
        $this->new_correct[$id] = $correct;
659
        $this->new_comment[$id] = $comment;
660
        $this->new_weighting[$id] = $weighting;
661
        $this->new_position[$id] = $position;
662
        $this->new_hotspot_coordinates[$id] = $new_hotspot_coordinates;
663
        $this->new_hotspot_type[$id] = $new_hotspot_type;
664
        $this->new_destination[$id] = $destination;
665
    }
666
667
    /**
668
     * Updates an answer.
669
     *
670
     * @author Toon Keppens
671
     *
672
     * @param int    $iid
673
     * @param string $answer
674
     * @param string $comment
675
     * @param string $correct
676
     * @param string $weighting
677
     * @param string $position
678
     * @param string $destination
679
     * @param string $hotSpotCoordinates
680
     * @param string $hotSpotType
681
     *
682
     * @return CQuizAnswer
683
     */
684
    public function updateAnswers(
685
        $iid,
686
        $answer,
687
        $comment,
688
        $correct,
689
        $weighting,
690
        $position,
691
        $destination,
692
        $hotSpotCoordinates,
693
        $hotSpotType
694
    ) {
695
        $em = Database::getManager();
696
697
        /** @var CQuizAnswer $quizAnswer */
698
        $quizAnswer = $em->find('ChamiloCourseBundle:CQuizAnswer', $iid);
699
        if ($quizAnswer) {
0 ignored issues
show
introduced by
$quizAnswer is of type Chamilo\CourseBundle\Entity\CQuizAnswer, thus it always evaluated to true.
Loading history...
700
            $quizAnswer
701
                ->setAnswer($answer)
702
                ->setComment($comment)
703
                ->setCorrect($correct)
704
                ->setPonderation($weighting)
705
                ->setPosition($position)
706
                ->setDestination($destination)
707
                ->setHotspotCoordinates($hotSpotCoordinates)
708
                ->setHotspotType($hotSpotType);
709
710
            $em->merge($quizAnswer);
711
            $em->flush();
712
713
            return $quizAnswer;
714
        }
715
716
        return false;
717
    }
718
719
    /**
720
     * Records answers into the data base.
721
     *
722
     * @author Olivier Brouckaert
723
     */
724
    public function save()
725
    {
726
        $answerTable = Database::get_course_table(TABLE_QUIZ_ANSWER);
727
        $em = Database::getManager();
728
        $questionId = (int) $this->questionId;
729
730
        $courseId = $this->course['real_id'];
731
        $answerList = [];
732
733
        for ($i = 1; $i <= $this->new_nbrAnswers; $i++) {
734
            $answer = $this->new_answer[$i];
735
            $correct = isset($this->new_correct[$i]) ? $this->new_correct[$i] : '';
736
            $comment = isset($this->new_comment[$i]) ? $this->new_comment[$i] : '';
737
            $weighting = isset($this->new_weighting[$i]) ? $this->new_weighting[$i] : '';
738
            $position = isset($this->new_position[$i]) ? $this->new_position[$i] : '';
739
            $hotspot_coordinates = isset($this->new_hotspot_coordinates[$i]) ? $this->new_hotspot_coordinates[$i] : '';
740
            $hotspot_type = isset($this->new_hotspot_type[$i]) ? $this->new_hotspot_type[$i] : '';
741
            $destination = isset($this->new_destination[$i]) ? $this->new_destination[$i] : '';
742
            $autoId = $this->selectAutoId($i);
743
            $iid = isset($this->iid[$i]) ? $this->iid[$i] : 0;
744
745
            if (!isset($this->position[$i])) {
746
                $quizAnswer = new CQuizAnswer();
747
                $quizAnswer
748
                    ->setIdAuto($autoId)
749
                    ->setCId($courseId)
750
                    ->setQuestionId($questionId)
751
                    ->setAnswer($answer)
752
                    ->setCorrect($correct)
753
                    ->setComment($comment)
754
                    ->setPonderation($weighting)
755
                    ->setPosition($position)
756
                    ->setHotspotCoordinates($hotspot_coordinates)
757
                    ->setHotspotType($hotspot_type)
758
                    ->setDestination($destination);
759
760
                $em->persist($quizAnswer);
761
                $em->flush();
762
763
                $iid = $quizAnswer->getId();
764
765
                if ($iid) {
766
                    $quizAnswer
767
                        ->setId($iid)
768
                        ->setIdAuto($iid);
769
770
                    $questionType = $this->getQuestionType();
771
                    if (in_array(
772
                        $questionType,
773
                        [MATCHING, MATCHING_DRAGGABLE, MATCHING_COMBINATION, MATCHING_DRAGGABLE_COMBINATION]
774
                    )) {
775
                        $answer = new Answer($this->questionId, $courseId, $this->exercise, false);
776
                        $answer->read();
777
                        $correctAnswerId = $answer->selectAnswerIdByPosition($correct);
778
779
                        // Continue to avoid matching question bug if $correctAnswerId returns false
780
                        // See : https://support.chamilo.org/issues/8334
781
                        if ($questionType == MATCHING && !$correctAnswerId) {
782
                            $em->merge($quizAnswer);
783
                            $em->flush();
784
                            continue;
785
                        }
786
                        $correctAnswerAutoId = $answer->selectAutoId($correct);
787
                        $quizAnswer->setCorrect($correctAnswerAutoId ? $correctAnswerAutoId : 0);
788
                    }
789
790
                    $em->merge($quizAnswer);
791
                    $em->flush();
792
                }
793
            } else {
794
                // https://support.chamilo.org/issues/6558
795
                // function updateAnswers already escape_string, error if we do it twice.
796
                // Feed function updateAnswers with none escaped strings
797
                $this->updateAnswers(
798
                    $iid,
799
                    $this->new_answer[$i],
800
                    $this->new_comment[$i],
801
                    $this->new_correct[$i],
802
                    $this->new_weighting[$i],
803
                    $this->new_position[$i],
804
                    $this->new_destination[$i],
805
                    $this->new_hotspot_coordinates[$i],
806
                    $this->new_hotspot_type[$i]
807
                );
808
            }
809
810
            $answerList[$i] = $iid;
811
        }
812
813
        $questionType = $this->getQuestionType();
814
815
        switch ($questionType) {
816
            case MATCHING_DRAGGABLE:
817
                foreach ($this->new_correct as $value => $status) {
818
                    if (!empty($status)) {
819
                        if (isset($answerList[$status])) {
820
                            $correct = $answerList[$status];
821
                        } else {
822
                            $correct = $status;
823
                        }
824
                        $myAutoId = $answerList[$value];
825
                        $sql = "UPDATE $answerTable
826
                            SET correct = '$correct'
827
                            WHERE
828
                                id_auto = $myAutoId
829
                            ";
830
                        Database::query($sql);
831
                    }
832
                }
833
                break;
834
            case DRAGGABLE:
835
                foreach ($this->new_correct as $value => $status) {
836
                    if (!empty($status)) {
837
                        $correct = $answerList[$status];
838
                        $myAutoId = $answerList[$value];
839
                        $sql = "UPDATE $answerTable
840
                            SET correct = '$correct'
841
                            WHERE
842
                                id_auto = $myAutoId
843
                            ";
844
                        Database::query($sql);
845
                    }
846
                }
847
                break;
848
        }
849
850
        if (count($this->position) > $this->new_nbrAnswers) {
851
            $i = $this->new_nbrAnswers + 1;
852
            while (isset($this->position[$i])) {
853
                $position = $this->position[$i];
854
                $sql = "DELETE FROM $answerTable
855
                        WHERE
856
                            c_id = {$this->course_id} AND
857
                            question_id = {$questionId} AND
858
                            position ='$position'";
859
                Database::query($sql);
860
                $i++;
861
            }
862
        }
863
864
        // moves $new_* arrays
865
        $this->answer = $this->new_answer;
866
        $this->correct = $this->new_correct;
867
        $this->comment = $this->new_comment;
868
        $this->weighting = $this->new_weighting;
869
        $this->position = $this->new_position;
870
        $this->hotspot_coordinates = $this->new_hotspot_coordinates;
871
        $this->hotspot_type = $this->new_hotspot_type;
872
        $this->nbrAnswers = $this->new_nbrAnswers;
873
        $this->destination = $this->new_destination;
874
875
        $this->cancel();
876
    }
877
878
    /**
879
     * Duplicates answers by copying them into another question.
880
     *
881
     * @author Olivier Brouckaert
882
     *
883
     * @param Question $newQuestion
884
     * @param array    $course_info destination course info (result of the function api_get_course_info() )
885
     */
886
    public function duplicate($newQuestion, $course_info = null)
887
    {
888
        $newQuestionId = $newQuestion->iid;
889
890
        if (empty($course_info)) {
891
            $course_info = $this->course;
892
        }
893
894
        $fixed_list = [];
895
        $tableAnswer = Database::get_course_table(TABLE_QUIZ_ANSWER);
896
897
        if (self::getQuestionType() == MULTIPLE_ANSWER_TRUE_FALSE ||
898
            self::getQuestionType() == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
899
        ) {
900
            // Selecting origin options
901
            $origin_options = Question::readQuestionOption(
902
                $this->selectQuestionId(),
903
                $this->course['real_id']
904
            );
905
906
            if (!empty($origin_options)) {
907
                foreach ($origin_options as $item) {
908
                    $new_option_list[] = $item['iid'];
909
                }
910
            }
911
912
            $destination_options = Question::readQuestionOption(
913
                $newQuestionId,
914
                $course_info['real_id']
915
            );
916
            $i = 0;
917
            if (!empty($destination_options)) {
918
                foreach ($destination_options as $item) {
919
                    $fixed_list[$new_option_list[$i]] = $item['iid'];
920
                    $i++;
921
                }
922
            }
923
        }
924
925
        // if at least one answer
926
        if ($this->nbrAnswers) {
927
            // inserts new answers into data base
928
            $courseId = $course_info['real_id'];
929
            $correctAnswers = [];
930
            $onlyAnswers = [];
931
            $allAnswers = [];
932
933
            $em = Database::getManager();
934
935
            if (in_array($newQuestion->type, [MATCHING, MATCHING_DRAGGABLE])) {
936
                $temp = [];
937
                for ($i = 1; $i <= $this->nbrAnswers; $i++) {
938
                    $answer = [
939
                        'iid' => $this->iid[$i],
940
                        'answer' => $this->answer[$i],
941
                        'correct' => $this->correct[$i],
942
                        'comment' => $this->comment[$i],
943
                        'weighting' => $this->weighting[$i],
944
                        'ponderation' => $this->weighting[$i],
945
                        'position' => $this->position[$i],
946
                        'hotspot_coordinates' => $this->hotspot_coordinates[$i],
947
                        'hotspot_type' => $this->hotspot_type[$i],
948
                        'destination' => $this->destination[$i],
949
                    ];
950
                    $temp[$answer['position']] = $answer;
951
                    $allAnswers[$this->iid[$i]] = $this->answer[$i];
952
                }
953
954
                foreach ($temp as $answer) {
955
                    if ($this->course['id'] != $course_info['id']) {
956
                        // check resources inside html from ckeditor tool and copy correct urls into recipient course
957
                        $answer['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
958
                            $answer['answer'],
959
                            $this->course['id'],
960
                            $course_info['id']
961
                        );
962
963
                        $answer['comment'] = DocumentManager::replaceUrlWithNewCourseCode(
964
                            $answer['comment'],
965
                            $this->course['id'],
966
                            $course_info['id']
967
                        );
968
                    }
969
970
                    $quizAnswer = new CQuizAnswer();
971
                    $quizAnswer
972
                        ->setCId($courseId)
973
                        ->setQuestionId($newQuestionId)
974
                        ->setAnswer($answer['answer'])
975
                        ->setCorrect($answer['correct'])
976
                        ->setComment($answer['comment'])
977
                        ->setPonderation($answer['ponderation'])
978
                        ->setPosition($answer['position'])
979
                        ->setHotspotCoordinates($answer['hotspot_coordinates'])
980
                        ->setHotspotType($answer['hotspot_type'])
981
                        ->setIdAuto(0);
982
983
                    $em->persist($quizAnswer);
984
                    $em->flush();
985
986
                    $answerId = $quizAnswer->getId();
987
988
                    if ($answerId) {
989
                        $quizAnswer
990
                            ->setId($answerId)
991
                            ->setIdAuto($answerId);
992
993
                        $em->merge($quizAnswer);
994
                        $em->flush();
995
996
                        $correctAnswers[$answerId] = $answer['correct'];
997
                        $onlyAnswers[$answerId] = $answer['answer'];
998
                    }
999
                }
1000
            } else {
1001
                for ($i = 1; $i <= $this->nbrAnswers; $i++) {
1002
                    if ($this->course['id'] != $course_info['id']) {
1003
                        $this->answer[$i] = DocumentManager::replaceUrlWithNewCourseCode(
1004
                            $this->answer[$i],
1005
                            $this->course['id'],
1006
                            $course_info['id']
1007
                        );
1008
                        $this->comment[$i] = DocumentManager::replaceUrlWithNewCourseCode(
1009
                            $this->comment[$i],
1010
                            $this->course['id'],
1011
                            $course_info['id']
1012
                        );
1013
                    }
1014
1015
                    $correct = $this->correct[$i];
1016
                    if ($newQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE ||
1017
                        $newQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
1018
                    ) {
1019
                        $correct = $fixed_list[intval($correct)];
1020
                    }
1021
1022
                    $quizAnswer = new CQuizAnswer();
1023
                    $quizAnswer
1024
                        ->setCId($courseId)
1025
                        ->setQuestionId($newQuestionId)
1026
                        ->setAnswer($this->answer[$i])
1027
                        ->setCorrect($correct)
1028
                        ->setComment($this->comment[$i])
1029
                        ->setPonderation($this->weighting[$i])
1030
                        ->setPosition($this->position[$i])
1031
                        ->setHotspotCoordinates($this->hotspot_coordinates[$i])
1032
                        ->setHotspotType($this->hotspot_type[$i])
1033
                        ->setDestination($this->destination[$i]);
1034
1035
                    $em->persist($quizAnswer);
1036
                    $em->flush();
1037
1038
                    $answerId = $quizAnswer->getId();
1039
                    $quizAnswer
1040
                        ->setId($answerId)
1041
                        ->setIdAuto($answerId);
1042
1043
                    $em->merge($quizAnswer);
1044
                    $em->flush();
1045
1046
                    $correctAnswers[$answerId] = $correct;
1047
                    $onlyAnswers[$answerId] = $this->answer[$i];
1048
                    $allAnswers[$this->iid[$i]] = $this->answer[$i];
1049
                }
1050
            }
1051
1052
            // Fix correct answers
1053
            if (in_array($newQuestion->type, [DRAGGABLE, MATCHING, MATCHING_DRAGGABLE])) {
1054
                $onlyAnswersFlip = array_flip($onlyAnswers);
1055
                foreach ($correctAnswers as $answer_id => $correct_answer) {
1056
                    $params = [];
1057
                    if (isset($allAnswers[$correct_answer]) &&
1058
                        isset($onlyAnswersFlip[$allAnswers[$correct_answer]])
1059
                    ) {
1060
                        $params['correct'] = $onlyAnswersFlip[$allAnswers[$correct_answer]];
1061
                        Database::update(
1062
                            $tableAnswer,
1063
                            $params,
1064
                            [
1065
                                'iid = ? ' => [
1066
                                    $answer_id,
1067
                                ],
1068
                            ]
1069
                        );
1070
                    }
1071
                }
1072
            }
1073
        }
1074
    }
1075
1076
    /**
1077
     * Get the necessary JavaScript for some answers.
1078
     *
1079
     * @return string
1080
     */
1081
    public function getJs()
1082
    {
1083
        return "<script>
1084
                $(window).on('load', function() {
1085
                    jsPlumb.ready(function() {
1086
                        if ($('#drag{$this->questionId}_question').length > 0) {
1087
                            MatchingDraggable.init('{$this->questionId}');
1088
                        }
1089
                    });
1090
                });
1091
            </script>";
1092
    }
1093
1094
    /**
1095
     * Check if a answer is correct by an answer auto id.
1096
     *
1097
     * @param int $needle The answer auto id
1098
     *
1099
     * @return bool
1100
     */
1101
    public function isCorrectByAutoId($needle)
1102
    {
1103
        $key = 0;
1104
        if (is_array($this->autoId)) {
1105
            foreach ($this->autoId as $autoIdKey => $autoId) {
1106
                if ($autoId == $needle) {
1107
                    $key = $autoIdKey;
1108
                }
1109
            }
1110
        }
1111
1112
        if (!$key) {
1113
            return false;
1114
        }
1115
1116
        return $this->isCorrect($key) ? true : false;
1117
    }
1118
}
1119