Passed
Pull Request — 1.11.x (#3871)
by Angel Fernando Quiroz
10:43
created

Answer::selectAnswerById()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 10
nc 3
nop 1
dl 0
loc 16
rs 9.9332
c 1
b 0
f 0
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
    public $autoId;
38
    /** @var int Number of answers in the question */
39
    public $nbrAnswers;
40
    public $new_nbrAnswers;
41
    public $new_destination; // id of the next question if feedback option is set to Directfeedback
42
    public $course; //Course information
43
    public $iid;
44
    public $questionJSId;
45
    public $standalone;
46
    /** @var Exercise|null */
47
    private $exercise;
48
49
    /**
50
     * @author Olivier Brouckaert
51
     *
52
     * @param int      $questionId that answers belong to
53
     * @param int      $course_id
54
     * @param Exercise $exercise
55
     * @param bool     $readAnswer
56
     */
57
    public function __construct($questionId, $course_id = 0, $exercise = null, $readAnswer = true)
58
    {
59
        $this->questionId = (int) $questionId;
60
        $this->answer = [];
61
        $this->correct = [];
62
        $this->comment = [];
63
        $this->weighting = [];
64
        $this->position = [];
65
        $this->hotspot_coordinates = [];
66
        $this->hotspot_type = [];
67
        $this->destination = [];
68
        // clears $new_* arrays
69
        $this->cancel();
70
71
        if (!empty($course_id)) {
72
            $courseInfo = api_get_course_info_by_id($course_id);
73
        } else {
74
            $courseInfo = api_get_course_info();
75
        }
76
77
        $this->course = $courseInfo;
78
        $this->course_id = $courseInfo['real_id'];
79
80
        if (empty($exercise)) {
81
            // fills arrays
82
            $objExercise = new Exercise($this->course_id);
83
            $exerciseId = isset($_REQUEST['exerciseId']) ? $_REQUEST['exerciseId'] : null;
84
            $objExercise->read($exerciseId, false);
85
        } else {
86
            $objExercise = $exercise;
87
        }
88
        $this->exercise = $objExercise;
89
90
        if ($readAnswer) {
91
            if ($objExercise->random_answers == '1' && $this->getQuestionType() != CALCULATED_ANSWER) {
92
                $this->readOrderedBy('rand()', ''); // randomize answers
93
            } else {
94
                $this->read(); // natural order
95
            }
96
        }
97
    }
98
99
    /**
100
     * Clears $new_* arrays.
101
     *
102
     * @author Olivier Brouckaert
103
     */
104
    public function cancel()
105
    {
106
        $this->new_answer = [];
107
        $this->new_correct = [];
108
        $this->new_comment = [];
109
        $this->new_weighting = [];
110
        $this->new_position = [];
111
        $this->new_hotspot_coordinates = [];
112
        $this->new_hotspot_type = [];
113
        $this->new_nbrAnswers = 0;
114
        $this->new_destination = [];
115
    }
116
117
    /**
118
     * Reads answer information from the database.
119
     *
120
     * @author Olivier Brouckaert
121
     */
122
    public function read()
123
    {
124
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
125
        $questionId = $this->questionId;
126
127
        $sql = "SELECT * FROM $table
128
                WHERE question_id = $questionId
129
                ORDER BY position";
130
131
        $result = Database::query($sql);
132
        $i = 1;
133
134
        // while a record is found
135
        while ($object = Database::fetch_object($result)) {
136
            $this->id[$i] = $object->iid;
137
            $this->iid[$i] = $object->iid;
138
            $this->answer[$i] = $object->answer;
139
            $this->correct[$i] = $object->correct;
140
            $this->comment[$i] = $object->comment;
141
            $this->weighting[$i] = $object->ponderation;
142
            $this->position[$i] = $object->position;
143
            $this->hotspot_coordinates[$i] = $object->hotspot_coordinates;
144
            $this->hotspot_type[$i] = $object->hotspot_type;
145
            $this->destination[$i] = $object->destination;
146
            $this->autoId[$i] = $object->id_auto;
147
            $i++;
148
        }
149
        $this->nbrAnswers = $i - 1;
150
    }
151
152
    /**
153
     * Get answers already added to question.
154
     *
155
     * @return array
156
     */
157
    public function getAnswers()
158
    {
159
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
160
        $questionId = $this->questionId;
161
162
        $sql = "SELECT * FROM $table
163
                WHERE question_id = $questionId
164
                ORDER BY position";
165
166
        $result = Database::query($sql);
167
168
        $answers = [];
169
170
        // while a record is found
171
        while ($answer = Database::fetch_assoc($result)) {
172
            $answers[] = $answer;
173
        }
174
175
        return $answers;
176
    }
177
178
    /**
179
     * @param int $id
180
     *
181
     * @return array
182
     */
183
    public function getAnswerByAutoId($id)
184
    {
185
        foreach ($this->autoId as $key => $autoId) {
186
            if ($autoId == $id) {
187
                return [
188
                    'answer' => $this->answer[$key],
189
                    'correct' => $this->correct[$key],
190
                    'comment' => $this->comment[$key],
191
                ];
192
            }
193
        }
194
195
        return [];
196
    }
197
198
    /**
199
     * returns all answer ids from this question Id.
200
     *
201
     * @author Yoselyn Castillo
202
     *
203
     * @return array - $id (answer ids)
204
     */
205
    public function selectAnswerId()
206
    {
207
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
208
        $questionId = $this->questionId;
209
210
        $sql = "SELECT iid FROM $table WHERE question_id = $questionId";
211
212
        $result = Database::query($sql);
213
        $id = [];
214
        // while a record is found
215
        if (Database::num_rows($result) > 0) {
216
            while ($object = Database::fetch_array($result)) {
217
                $id[] = $object['iid'];
218
            }
219
        }
220
221
        return $id;
222
    }
223
224
    /**
225
     * Reads answer information from the data base ordered by parameter.
226
     *
227
     * @param string $field Field we want to order by
228
     * @param string $order DESC or ASC
229
     *
230
     * @return bool
231
     *
232
     * @author Frederic Vauthier
233
     */
234
    public function readOrderedBy($field, $order = 'ASC')
235
    {
236
        $field = Database::escape_string($field);
237
        if (empty($field)) {
238
            $field = 'position';
239
        }
240
241
        if ('ASC' != $order && 'DESC' != $order) {
242
            $order = 'ASC';
243
        }
244
245
        $TBL_ANSWER = Database::get_course_table(TABLE_QUIZ_ANSWER);
246
        $TBL_QUESTION = Database::get_course_table(TABLE_QUIZ_QUESTION);
247
        $questionId = (int) $this->questionId;
248
249
        $sql = "SELECT type FROM $TBL_QUESTION
250
                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
    public function selectAnswerByAutoId($auto_id)
399
    {
400
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
401
        $auto_id = (int) $auto_id;
402
        $sql = "SELECT iid, answer, id_auto FROM $table
403
                WHERE c_id = {$this->course_id} AND id_auto='$auto_id'";
404
        $rs = Database::query($sql);
405
406
        if (Database::num_rows($rs) > 0) {
407
            return Database::fetch_array($rs, 'ASSOC');
408
        }
409
410
        return false;
411
    }
412
413
    /**
414
     * return array answer by iid. Else return a bool.
415
     *
416
     * @param int $iid
417
     *
418
     * @return array
419
     */
420
    public function selectAnswerById($id)
421
    {
422
        if (empty($id)) {
423
            return false;
424
        }
425
        $table = Database::get_course_table(TABLE_QUIZ_ANSWER);
426
        $id = (int) $id;
427
        $sql = "SELECT iid, answer, id_auto FROM $table
428
                WHERE iid = $id";
429
        $rs = Database::query($sql);
430
431
        if (Database::num_rows($rs) > 0) {
432
            return Database::fetch_array($rs, 'ASSOC');
433
        }
434
435
        return false;
436
    }
437
438
    /**
439
     * returns the answer title from an answer's position.
440
     *
441
     * @author Yannick Warnier
442
     *
443
     * @param - integer $pos - answer ID
444
     *
445
     * @return bool - answer title
446
     */
447
    public function selectAnswerIdByPosition($pos)
448
    {
449
        foreach ($this->position as $k => $v) {
450
            if ($v != $pos) {
451
                continue;
452
            }
453
454
            return $k;
455
        }
456
457
        return false;
458
    }
459
460
    /**
461
     * Returns a list of answers.
462
     *
463
     * @author Yannick Warnier <[email protected]>
464
     *
465
     * @param bool $decode
466
     *
467
     * @return array List of answers where each answer is an array
468
     *               of (id, answer, comment, grade) and grade=weighting
469
     */
470
    public function getAnswersList($decode = false)
471
    {
472
        $list = [];
473
        for ($i = 1; $i <= $this->nbrAnswers; $i++) {
474
            if (!empty($this->answer[$i])) {
475
                //Avoid problems when parsing elements with accents
476
                if ($decode) {
477
                    $this->answer[$i] = api_html_entity_decode(
478
                        $this->answer[$i],
479
                        ENT_QUOTES,
480
                        api_get_system_encoding()
481
                    );
482
                    $this->comment[$i] = api_html_entity_decode(
483
                        $this->comment[$i],
484
                        ENT_QUOTES,
485
                        api_get_system_encoding()
486
                    );
487
                }
488
489
                $list[] = [
490
                    'iid' => $i,
491
                    'answer' => $this->answer[$i],
492
                    'comment' => $this->comment[$i],
493
                    'grade' => $this->weighting[$i],
494
                    'hotspot_coord' => $this->hotspot_coordinates[$i],
495
                    'hotspot_type' => $this->hotspot_type[$i],
496
                    'correct' => $this->correct[$i],
497
                    'destination' => $this->destination[$i],
498
                ];
499
            }
500
        }
501
502
        return $list;
503
    }
504
505
    /**
506
     * Returns a list of grades.
507
     *
508
     * @author Yannick Warnier <[email protected]>
509
     *
510
     * @return array List of grades where grade=weighting (?)
511
     */
512
    public function getGradesList()
513
    {
514
        $list = [];
515
        for ($i = 0; $i < $this->nbrAnswers; $i++) {
516
            if (!empty($this->answer[$i])) {
517
                $list[$i] = $this->weighting[$i];
518
            }
519
        }
520
521
        return $list;
522
    }
523
524
    /**
525
     * Returns the question type.
526
     *
527
     * @author    Yannick Warnier <[email protected]>
528
     *
529
     * @return int The type of the question this answer is bound to
530
     */
531
    public function getQuestionType()
532
    {
533
        $table = Database::get_course_table(TABLE_QUIZ_QUESTION);
534
        $sql = "SELECT type FROM $table
535
                WHERE iid = {$this->questionId}";
536
        $res = Database::query($sql);
537
        if (Database::num_rows($res) <= 0) {
538
            return null;
539
        }
540
        $row = Database::fetch_array($res);
541
542
        return (int) $row['type'];
543
    }
544
545
    /**
546
     * tells if answer is correct or not.
547
     *
548
     * @author Olivier Brouckaert
549
     *
550
     * @param - integer $id - answer ID
551
     *
552
     * @return int - 0 if bad answer, not 0 if good answer
553
     */
554
    public function isCorrect($id)
555
    {
556
        return isset($this->correct[$id]) ? $this->correct[$id] : null;
557
    }
558
559
    /**
560
     * returns answer comment.
561
     *
562
     * @author Olivier Brouckaert
563
     *
564
     * @param - integer $id - answer ID
565
     *
566
     * @return string - answer comment
567
     */
568
    public function selectComment($id)
569
    {
570
        return isset($this->comment[$id]) ? $this->comment[$id] : null;
571
    }
572
573
    /**
574
     * returns answer weighting.
575
     *
576
     * @author Olivier Brouckaert
577
     *
578
     * @param - integer $id - answer ID
579
     *
580
     * @return int - answer weighting
581
     */
582
    public function selectWeighting($id)
583
    {
584
        return isset($this->weighting[$id]) ? $this->weighting[$id] : null;
585
    }
586
587
    /**
588
     * returns answer position.
589
     *
590
     * @author Olivier Brouckaert
591
     *
592
     * @param - integer $id - answer ID
593
     *
594
     * @return int - answer position
595
     */
596
    public function selectPosition($id)
597
    {
598
        return isset($this->position[$id]) ? $this->position[$id] : null;
599
    }
600
601
    /**
602
     * returns answer hotspot coordinates.
603
     *
604
     * @author Olivier Brouckaert
605
     *
606
     * @param int $id Answer ID
607
     *
608
     * @return int Answer position
609
     */
610
    public function selectHotspotCoordinates($id)
611
    {
612
        return isset($this->hotspot_coordinates[$id]) ? $this->hotspot_coordinates[$id] : null;
613
    }
614
615
    /**
616
     * returns answer hotspot type.
617
     *
618
     * @author Toon Keppens
619
     *
620
     * @param int $id Answer ID
621
     *
622
     * @return int Answer position
623
     */
624
    public function selectHotspotType($id)
625
    {
626
        return isset($this->hotspot_type[$id]) ? $this->hotspot_type[$id] : null;
627
    }
628
629
    /**
630
     * Creates a new answer.
631
     *
632
     * @author Olivier Brouckaert
633
     *
634
     * @param string $answer                  answer title
635
     * @param int    $correct                 0 if bad answer, not 0 if good answer
636
     * @param string $comment                 answer comment
637
     * @param int    $weighting               answer weighting
638
     * @param int    $position                answer position
639
     * @param array  $new_hotspot_coordinates Coordinates for hotspot exercises (optional)
640
     * @param int    $new_hotspot_type        Type for hotspot exercises (optional)
641
     * @param string $destination
642
     */
643
    public function createAnswer(
644
        $answer,
645
        $correct,
646
        $comment,
647
        $weighting,
648
        $position,
649
        $new_hotspot_coordinates = null,
650
        $new_hotspot_type = null,
651
        $destination = ''
652
    ) {
653
        $this->new_nbrAnswers++;
654
        $id = $this->new_nbrAnswers;
655
        $this->new_answer[$id] = $answer;
656
        $this->new_correct[$id] = $correct;
657
        $this->new_comment[$id] = $comment;
658
        $this->new_weighting[$id] = $weighting;
659
        $this->new_position[$id] = $position;
660
        $this->new_hotspot_coordinates[$id] = $new_hotspot_coordinates;
661
        $this->new_hotspot_type[$id] = $new_hotspot_type;
662
        $this->new_destination[$id] = $destination;
663
    }
664
665
    /**
666
     * Updates an answer.
667
     *
668
     * @author Toon Keppens
669
     *
670
     * @param int    $iid
671
     * @param string $answer
672
     * @param string $comment
673
     * @param string $correct
674
     * @param string $weighting
675
     * @param string $position
676
     * @param string $destination
677
     * @param string $hotSpotCoordinates
678
     * @param string $hotSpotType
679
     *
680
     * @return CQuizAnswer
681
     */
682
    public function updateAnswers(
683
        $iid,
684
        $answer,
685
        $comment,
686
        $correct,
687
        $weighting,
688
        $position,
689
        $destination,
690
        $hotSpotCoordinates,
691
        $hotSpotType
692
    ) {
693
        $em = Database::getManager();
694
695
        /** @var CQuizAnswer $quizAnswer */
696
        $quizAnswer = $em->find('ChamiloCourseBundle:CQuizAnswer', $iid);
697
        if ($quizAnswer) {
0 ignored issues
show
introduced by
$quizAnswer is of type Chamilo\CourseBundle\Entity\CQuizAnswer, thus it always evaluated to true.
Loading history...
698
            $quizAnswer
699
                ->setAnswer($answer)
700
                ->setComment($comment)
701
                ->setCorrect($correct)
702
                ->setPonderation($weighting)
703
                ->setPosition($position)
704
                ->setDestination($destination)
705
                ->setHotspotCoordinates($hotSpotCoordinates)
706
                ->setHotspotType($hotSpotType);
707
708
            $em->merge($quizAnswer);
709
            $em->flush();
710
711
            return $quizAnswer;
712
        }
713
714
        return false;
715
    }
716
717
    /**
718
     * Records answers into the data base.
719
     *
720
     * @author Olivier Brouckaert
721
     */
722
    public function save()
723
    {
724
        $answerTable = Database::get_course_table(TABLE_QUIZ_ANSWER);
725
        $em = Database::getManager();
726
        $questionId = (int) $this->questionId;
727
728
        $courseId = $this->course['real_id'];
729
        $answerList = [];
730
731
        for ($i = 1; $i <= $this->new_nbrAnswers; $i++) {
732
            $answer = $this->new_answer[$i];
733
            $correct = isset($this->new_correct[$i]) ? $this->new_correct[$i] : '';
734
            $comment = isset($this->new_comment[$i]) ? $this->new_comment[$i] : '';
735
            $weighting = isset($this->new_weighting[$i]) ? $this->new_weighting[$i] : '';
736
            $position = isset($this->new_position[$i]) ? $this->new_position[$i] : '';
737
            $hotspot_coordinates = isset($this->new_hotspot_coordinates[$i]) ? $this->new_hotspot_coordinates[$i] : '';
738
            $hotspot_type = isset($this->new_hotspot_type[$i]) ? $this->new_hotspot_type[$i] : '';
739
            $destination = isset($this->new_destination[$i]) ? $this->new_destination[$i] : '';
740
            $autoId = $this->selectAutoId($i);
741
            $iid = isset($this->iid[$i]) ? $this->iid[$i] : 0;
742
743
            if (!isset($this->position[$i])) {
744
                $quizAnswer = new CQuizAnswer();
745
                $quizAnswer
746
                    ->setIdAuto($autoId)
747
                    ->setCId($courseId)
748
                    ->setQuestionId($questionId)
749
                    ->setAnswer($answer)
750
                    ->setCorrect($correct)
751
                    ->setComment($comment)
752
                    ->setPonderation($weighting)
753
                    ->setPosition($position)
754
                    ->setHotspotCoordinates($hotspot_coordinates)
755
                    ->setHotspotType($hotspot_type)
756
                    ->setDestination($destination);
757
758
                $em->persist($quizAnswer);
759
                $em->flush();
760
761
                $iid = $quizAnswer->getId();
762
763
                if ($iid) {
764
                    $quizAnswer
765
                        ->setId($iid)
766
                        ->setIdAuto($iid);
767
768
                    $questionType = $this->getQuestionType();
769
                    if (in_array(
770
                        $questionType,
771
                        [MATCHING, MATCHING_DRAGGABLE]
772
                    )) {
773
                        $answer = new Answer($this->questionId, $courseId, $this->exercise, false);
774
                        $answer->read();
775
                        $correctAnswerId = $answer->selectAnswerIdByPosition($correct);
776
777
                        // Continue to avoid matching question bug if $correctAnswerId returns false
778
                        // See : https://support.chamilo.org/issues/8334
779
                        if ($questionType == MATCHING && !$correctAnswerId) {
780
                            $em->merge($quizAnswer);
781
                            $em->flush();
782
                            continue;
783
                        }
784
                        $correctAnswerAutoId = $answer->selectAutoId($correct);
785
                        $quizAnswer->setCorrect($correctAnswerAutoId ? $correctAnswerAutoId : 0);
786
                    }
787
788
                    $em->merge($quizAnswer);
789
                    $em->flush();
790
                }
791
            } else {
792
                // https://support.chamilo.org/issues/6558
793
                // function updateAnswers already escape_string, error if we do it twice.
794
                // Feed function updateAnswers with none escaped strings
795
                $this->updateAnswers(
796
                    $iid,
797
                    $this->new_answer[$i],
798
                    $this->new_comment[$i],
799
                    $this->new_correct[$i],
800
                    $this->new_weighting[$i],
801
                    $this->new_position[$i],
802
                    $this->new_destination[$i],
803
                    $this->new_hotspot_coordinates[$i],
804
                    $this->new_hotspot_type[$i]
805
                );
806
            }
807
808
            $answerList[$i] = $iid;
809
        }
810
811
        $questionType = $this->getQuestionType();
812
813
        switch ($questionType) {
814
            case MATCHING_DRAGGABLE:
815
                foreach ($this->new_correct as $value => $status) {
816
                    if (!empty($status)) {
817
                        if (isset($answerList[$status])) {
818
                            $correct = $answerList[$status];
819
                        } else {
820
                            $correct = $status;
821
                        }
822
                        $myAutoId = $answerList[$value];
823
                        $sql = "UPDATE $answerTable
824
                            SET correct = '$correct'
825
                            WHERE
826
                                id_auto = $myAutoId
827
                            ";
828
                        Database::query($sql);
829
                    }
830
                }
831
                break;
832
            case DRAGGABLE:
833
                foreach ($this->new_correct as $value => $status) {
834
                    if (!empty($status)) {
835
                        $correct = $answerList[$status];
836
                        $myAutoId = $answerList[$value];
837
                        $sql = "UPDATE $answerTable
838
                            SET correct = '$correct'
839
                            WHERE
840
                                id_auto = $myAutoId
841
                            ";
842
                        Database::query($sql);
843
                    }
844
                }
845
                break;
846
        }
847
848
        if (count($this->position) > $this->new_nbrAnswers) {
849
            $i = $this->new_nbrAnswers + 1;
850
            while ($this->position[$i]) {
851
                $position = $this->position[$i];
852
                $sql = "DELETE FROM $answerTable
853
                        WHERE
854
                            c_id = {$this->course_id} AND
855
                            question_id = {$questionId} AND
856
                            position ='$position'";
857
                Database::query($sql);
858
                $i++;
859
            }
860
        }
861
862
        // moves $new_* arrays
863
        $this->answer = $this->new_answer;
864
        $this->correct = $this->new_correct;
865
        $this->comment = $this->new_comment;
866
        $this->weighting = $this->new_weighting;
867
        $this->position = $this->new_position;
868
        $this->hotspot_coordinates = $this->new_hotspot_coordinates;
869
        $this->hotspot_type = $this->new_hotspot_type;
870
        $this->nbrAnswers = $this->new_nbrAnswers;
871
        $this->destination = $this->new_destination;
872
873
        $this->cancel();
874
    }
875
876
    /**
877
     * Duplicates answers by copying them into another question.
878
     *
879
     * @author Olivier Brouckaert
880
     *
881
     * @param Question $newQuestion
882
     * @param array    $course_info destination course info (result of the function api_get_course_info() )
883
     */
884
    public function duplicate($newQuestion, $course_info = null)
885
    {
886
        $newQuestionId = $newQuestion->iid;
887
888
        if (empty($course_info)) {
889
            $course_info = $this->course;
890
        }
891
892
        $fixed_list = [];
893
        $tableAnswer = Database::get_course_table(TABLE_QUIZ_ANSWER);
894
895
        if (self::getQuestionType() == MULTIPLE_ANSWER_TRUE_FALSE ||
896
            self::getQuestionType() == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
897
        ) {
898
            // Selecting origin options
899
            $origin_options = Question::readQuestionOption(
900
                $this->selectQuestionId(),
901
                $this->course['real_id']
902
            );
903
904
            if (!empty($origin_options)) {
905
                foreach ($origin_options as $item) {
906
                    $new_option_list[] = $item['iid'];
907
                }
908
            }
909
910
            $destination_options = Question::readQuestionOption(
911
                $newQuestionId,
912
                $course_info['real_id']
913
            );
914
            $i = 0;
915
            if (!empty($destination_options)) {
916
                foreach ($destination_options as $item) {
917
                    $fixed_list[$new_option_list[$i]] = $item['iid'];
918
                    $i++;
919
                }
920
            }
921
        }
922
923
        // if at least one answer
924
        if ($this->nbrAnswers) {
925
            // inserts new answers into data base
926
            $courseId = $course_info['real_id'];
927
            $correctAnswers = [];
928
            $onlyAnswers = [];
929
            $allAnswers = [];
930
931
            $em = Database::getManager();
932
933
            if (in_array($newQuestion->type, [MATCHING, MATCHING_DRAGGABLE])) {
934
                $temp = [];
935
                for ($i = 1; $i <= $this->nbrAnswers; $i++) {
936
                    $answer = [
937
                        'iid' => $this->iid[$i],
938
                        'answer' => $this->answer[$i],
939
                        'correct' => $this->correct[$i],
940
                        'comment' => $this->comment[$i],
941
                        'weighting' => $this->weighting[$i],
942
                        'ponderation' => $this->weighting[$i],
943
                        'position' => $this->position[$i],
944
                        'hotspot_coordinates' => $this->hotspot_coordinates[$i],
945
                        'hotspot_type' => $this->hotspot_type[$i],
946
                        'destination' => $this->destination[$i],
947
                    ];
948
                    $temp[$answer['position']] = $answer;
949
                    $allAnswers[$this->iid[$i]] = $this->answer[$i];
950
                }
951
952
                foreach ($temp as $answer) {
953
                    if ($this->course['id'] != $course_info['id']) {
954
                        // check resources inside html from ckeditor tool and copy correct urls into recipient course
955
                        $answer['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
956
                            $answer['answer'],
957
                            $this->course['id'],
958
                            $course_info['id']
959
                        );
960
961
                        $answer['comment'] = DocumentManager::replaceUrlWithNewCourseCode(
962
                            $answer['comment'],
963
                            $this->course['id'],
964
                            $course_info['id']
965
                        );
966
                    }
967
968
                    $quizAnswer = new CQuizAnswer();
969
                    $quizAnswer
970
                        ->setCId($courseId)
971
                        ->setQuestionId($newQuestionId)
972
                        ->setAnswer($answer['answer'])
973
                        ->setCorrect($answer['correct'])
974
                        ->setComment($answer['comment'])
975
                        ->setPonderation($answer['ponderation'])
976
                        ->setPosition($answer['position'])
977
                        ->setHotspotCoordinates($answer['hotspot_coordinates'])
978
                        ->setHotspotType($answer['hotspot_type'])
979
                        ->setIdAuto(0);
980
981
                    $em->persist($quizAnswer);
982
                    $em->flush();
983
984
                    $answerId = $quizAnswer->getId();
985
986
                    if ($answerId) {
987
                        $quizAnswer
988
                            ->setId($answerId)
989
                            ->setIdAuto($answerId);
990
991
                        $em->merge($quizAnswer);
992
                        $em->flush();
993
994
                        $correctAnswers[$answerId] = $answer['correct'];
995
                        $onlyAnswers[$answerId] = $answer['answer'];
996
                    }
997
                }
998
            } else {
999
                for ($i = 1; $i <= $this->nbrAnswers; $i++) {
1000
                    if ($this->course['id'] != $course_info['id']) {
1001
                        $this->answer[$i] = DocumentManager::replaceUrlWithNewCourseCode(
1002
                            $this->answer[$i],
1003
                            $this->course['id'],
1004
                            $course_info['id']
1005
                        );
1006
                        $this->comment[$i] = DocumentManager::replaceUrlWithNewCourseCode(
1007
                            $this->comment[$i],
1008
                            $this->course['id'],
1009
                            $course_info['id']
1010
                        );
1011
                    }
1012
1013
                    $correct = $this->correct[$i];
1014
                    if ($newQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE ||
1015
                        $newQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
1016
                    ) {
1017
                        $correct = $fixed_list[intval($correct)];
1018
                    }
1019
1020
                    $quizAnswer = new CQuizAnswer();
1021
                    $quizAnswer
1022
                        ->setCId($courseId)
1023
                        ->setQuestionId($newQuestionId)
1024
                        ->setAnswer($this->answer[$i])
1025
                        ->setCorrect($correct)
1026
                        ->setComment($this->comment[$i])
1027
                        ->setPonderation($this->weighting[$i])
1028
                        ->setPosition($this->position[$i])
1029
                        ->setHotspotCoordinates($this->hotspot_coordinates[$i])
1030
                        ->setHotspotType($this->hotspot_type[$i])
1031
                        ->setDestination($this->destination[$i]);
1032
1033
                    $em->persist($quizAnswer);
1034
                    $em->flush();
1035
1036
                    $answerId = $quizAnswer->getId();
1037
                    $quizAnswer
1038
                        ->setId($answerId)
1039
                        ->setIdAuto($answerId);
1040
1041
                    $em->merge($quizAnswer);
1042
                    $em->flush();
1043
1044
                    $correctAnswers[$answerId] = $correct;
1045
                    $onlyAnswers[$answerId] = $this->answer[$i];
1046
                    $allAnswers[$this->iid[$i]] = $this->answer[$i];
1047
                }
1048
            }
1049
1050
            // Fix correct answers
1051
            if (in_array($newQuestion->type, [DRAGGABLE, MATCHING, MATCHING_DRAGGABLE])) {
1052
                $onlyAnswersFlip = array_flip($onlyAnswers);
1053
                foreach ($correctAnswers as $answer_id => $correct_answer) {
1054
                    $params = [];
1055
                    if (isset($allAnswers[$correct_answer]) &&
1056
                        isset($onlyAnswersFlip[$allAnswers[$correct_answer]])
1057
                    ) {
1058
                        $params['correct'] = $onlyAnswersFlip[$allAnswers[$correct_answer]];
1059
                        Database::update(
1060
                            $tableAnswer,
1061
                            $params,
1062
                            [
1063
                                'iid = ? AND c_id = ? AND question_id = ? ' => [
1064
                                    $answer_id,
1065
                                    $courseId,
1066
                                    $newQuestionId,
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