Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/exercise/answer.class.php (1 issue)

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
$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]
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 ($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