Completed
Push — master ( 27e209...a08afa )
by Julito
186:04 queued 150:53
created

Answer::createAnswer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 8
dl 0
loc 20
rs 9.4285
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
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CourseBundle\Entity\CQuizAnswer;
5
6
/**
7
 * Class Answer
8
 * Allows to instantiate an object of type Answer
9
 * 5 arrays are created to receive the attributes of each answer belonging to a specified question
10
 * @package chamilo.exercise
11
 *
12
 * @author Olivier Brouckaert
13
 */
14
class Answer
15
{
16
    public $questionId;
17
18
    // these are arrays
19
    public $answer;
20
    public $correct;
21
    public $comment;
22
    public $weighting;
23
    public $position;
24
    public $hotspot_coordinates;
25
    public $hotspot_type;
26
    public $destination;
27
    // these arrays are used to save temporarily new answers
28
    // then they are moved into the arrays above or deleted in the event of cancellation
29
    public $new_answer;
30
    public $new_correct;
31
    public $new_comment;
32
    public $new_weighting;
33
    public $new_position;
34
    public $new_hotspot_coordinates;
35
    public $new_hotspot_type;
36
    public $autoId;
37
    public $nbrAnswers;
38
    public $new_nbrAnswers;
39
    public $new_destination; // id of the next question if feedback option is set to Directfeedback
40
    public $course; //Course information
41
    public $iid;
42
    public $questionJSId;
43
    public $standalone;
44
45
    /**
46
     * constructor of the class
47
     *
48
     * @author Olivier Brouckaert
49
     * @param int $questionId that answers belong to
50
     * @param int $course_id
51
     * @param Exercise $exercise
52
     */
53
    public function __construct($questionId, $course_id = 0, $exercise = null)
54
    {
55
        $this->questionId = intval($questionId);
56
        $this->answer = [];
57
        $this->correct = [];
58
        $this->comment = [];
59
        $this->weighting = [];
60
        $this->position = [];
61
        $this->hotspot_coordinates = [];
62
        $this->hotspot_type = [];
63
        $this->destination = [];
64
        // clears $new_* arrays
65
        $this->cancel();
66
67
        if (!empty($course_id)) {
68
            $courseInfo = api_get_course_info_by_id($course_id);
69
        } else {
70
            $courseInfo = api_get_course_info();
71
        }
72
73
        $this->course = $courseInfo;
74
        $this->course_id = $courseInfo['real_id'];
0 ignored issues
show
Bug Best Practice introduced by
The property course_id does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
75
76
        if (empty($exercise)) {
77
            // fills arrays
78
            $objExercise = new Exercise($this->course_id);
79
            $exerciseId = isset($_REQUEST['exerciseId']) ? $_REQUEST['exerciseId'] : null;
80
            $objExercise->read($exerciseId);
81
        } else {
82
            $objExercise = $exercise;
83
        }
84
85
        if ($objExercise->random_answers == '1' && $this->getQuestionType() != CALCULATED_ANSWER) {
86
            $this->readOrderedBy('rand()', ''); // randomize answers
87
        } else {
88
            $this->read(); // natural order
89
        }
90
    }
91
92
    /**
93
     * Clears $new_* arrays
94
     *
95
     * @author Olivier Brouckaert
96
     */
97
    public function cancel()
98
    {
99
        $this->new_answer = [];
100
        $this->new_correct = [];
101
        $this->new_comment = [];
102
        $this->new_weighting = [];
103
        $this->new_position = [];
104
        $this->new_hotspot_coordinates = [];
105
        $this->new_hotspot_type = [];
106
        $this->new_nbrAnswers = 0;
107
        $this->new_destination = [];
108
    }
109
110
    /**
111
     * Reads answer information from the database
112
     *
113
     * @author Olivier Brouckaert
114
     */
115
    public function read()
116
    {
117
        $TBL_ANSWER = Database::get_course_table(TABLE_QUIZ_ANSWER);
118
        $questionId = $this->questionId;
119
120
        $sql = "SELECT * FROM $TBL_ANSWER
121
                WHERE
122
                    c_id = {$this->course_id} AND
123
                    question_id ='".$questionId."'
124
                ORDER BY position";
125
126
        $result = Database::query($sql);
127
        $i = 1;
128
129
        // while a record is found
130
        while ($object = Database::fetch_object($result)) {
131
            $this->id[$i] = $object->id;
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
132
            $this->answer[$i] = $object->answer;
133
            $this->correct[$i] = $object->correct;
134
            $this->comment[$i] = $object->comment;
135
            $this->weighting[$i] = $object->ponderation;
136
            $this->position[$i] = $object->position;
137
            $this->hotspot_coordinates[$i] = $object->hotspot_coordinates;
138
            $this->hotspot_type[$i] = $object->hotspot_type;
139
            $this->destination[$i] = $object->destination;
140
            $this->autoId[$i] = $object->id_auto;
141
            $this->iid[$i] = $object->iid;
142
            $i++;
143
        }
144
        $this->nbrAnswers = $i - 1;
145
    }
146
147
    /**
148
     * @param int $id
149
     *
150
     * @return array
151
     */
152
    public function getAnswerByAutoId($id)
153
    {
154
        foreach ($this->autoId as $key => $autoId) {
155
            if ($autoId == $id) {
156
                $result = [
157
                    'answer' => $this->answer[$key],
158
                    'correct' => $this->correct[$key],
159
                    'comment' => $this->comment[$key],
160
                ];
161
162
                return $result;
163
            }
164
        }
165
166
        return [];
167
    }
168
169
    /**
170
    * returns all answer ids from this question Id
171
    *
172
    * @author Yoselyn Castillo
173
    * @return array - $id (answer ids)
174
    */
175
    public function selectAnswerId()
176
    {
177
        $TBL_ANSWER = Database::get_course_table(TABLE_QUIZ_ANSWER);
178
        $questionId = $this->questionId;
179
180
        $sql = "SELECT id FROM
181
              $TBL_ANSWER
182
              WHERE c_id = {$this->course_id} AND question_id ='".$questionId."'";
183
184
        $result = Database::query($sql);
185
        $id = [];
186
        // while a record is found
187
        if (Database::num_rows($result) > 0) {
188
            while ($object = Database::fetch_array($result)) {
189
                $id[] = $object['id'];
190
            }
191
        }
192
193
        return $id;
194
    }
195
196
    /**
197
     * Reads answer information from the data base ordered by parameter
198
     * @param string $field Field we want to order by
199
     * @param string $order DESC or ASC
200
     * @return bool
201
     *
202
     * @author Frederic Vauthier
203
     */
204
    public function readOrderedBy($field, $order = 'ASC')
205
    {
206
        $field = Database::escape_string($field);
207
        if (empty($field)) {
208
            $field = 'position';
209
        }
210
211
        if ($order != 'ASC' && $order != 'DESC') {
212
            $order = 'ASC';
213
        }
214
215
        $TBL_ANSWER = Database::get_course_table(TABLE_QUIZ_ANSWER);
216
        $TBL_QUIZ = Database::get_course_table(TABLE_QUIZ_QUESTION);
217
        $questionId = intval($this->questionId);
218
219
        $sql = "SELECT type FROM $TBL_QUIZ
220
                WHERE c_id = {$this->course_id} AND id = $questionId";
221
        $result_question = Database::query($sql);
222
        $questionType = Database::fetch_array($result_question);
223
224
        if ($questionType['type'] == DRAGGABLE) {
225
            // Random is done by submit.js.tpl
226
            $this->read();
227
228
            return true;
229
        }
230
231
        $sql = "SELECT
232
                    answer,
233
                    correct,
234
                    comment,
235
                    ponderation,
236
                    position,
237
                    hotspot_coordinates,
238
                    hotspot_type,
239
                    destination,
240
                    id_auto,
241
                    iid
242
                FROM $TBL_ANSWER
243
                WHERE
244
                    c_id = {$this->course_id} AND
245
                    question_id='".$questionId."'
246
                ORDER BY $field $order";
247
        $result = Database::query($sql);
248
249
        $i = 1;
250
        // while a record is found
251
        $doubt_data = null;
252
        while ($object = Database::fetch_object($result)) {
253
            if ($questionType['type'] == UNIQUE_ANSWER_NO_OPTION && $object->position == 666) {
254
                $doubt_data = $object;
255
                continue;
256
            }
257
            $this->answer[$i] = $object->answer;
258
            $this->correct[$i] = $object->correct;
259
            $this->comment[$i] = $object->comment;
260
            $this->weighting[$i] = $object->ponderation;
261
            $this->position[$i] = $object->position;
262
            $this->hotspot_coordinates[$i] = $object->hotspot_coordinates;
263
            $this->hotspot_type[$i] = $object->hotspot_type;
264
            $this->destination[$i] = $object->destination;
265
            $this->autoId[$i] = $object->id_auto;
266
            $this->iid[$i] = $object->iid;
267
            $i++;
268
        }
269
270
        if ($questionType['type'] == UNIQUE_ANSWER_NO_OPTION && !empty($doubt_data)) {
271
            $this->answer[$i] = $doubt_data->answer;
272
            $this->correct[$i] = $doubt_data->correct;
273
            $this->comment[$i] = $doubt_data->comment;
274
            $this->weighting[$i] = $doubt_data->ponderation;
275
            $this->position[$i] = $doubt_data->position;
276
            $this->hotspot_coordinates[$i] = isset($object->hotspot_coordinates) ? $object->hotspot_coordinates : 0;
277
            $this->hotspot_type[$i] = isset($object->hotspot_type) ? $object->hotspot_type : 0;
278
            $this->destination[$i] = $doubt_data->destination;
279
            $this->autoId[$i] = $doubt_data->id_auto;
280
            $this->iid[$i] = $doubt_data->iid;
281
            $i++;
282
        }
283
        $this->nbrAnswers = $i - 1;
284
285
        return true;
286
    }
287
288
    /**
289
     * returns the autoincrement id
290
     *
291
     * @author Juan Carlos Ra�a
292
     * @return integer - answer num
293
     */
294
    public function selectAutoId($id)
295
    {
296
        return isset($this->autoId[$id]) ? $this->autoId[$id] : 0;
297
    }
298
299
    /**
300
     * returns the number of answers in this question
301
     *
302
     * @author Olivier Brouckaert
303
     * @return integer - number of answers
304
     */
305
    public function selectNbrAnswers()
306
    {
307
        return $this->nbrAnswers;
308
    }
309
310
    /**
311
     * returns the question ID which the answers belong to
312
     *
313
     * @author Olivier Brouckaert
314
     * @return integer - the question ID
315
     */
316
    public function selectQuestionId()
317
    {
318
        return $this->questionId;
319
    }
320
321
    /**
322
     * returns the question ID of the destination question
323
     *
324
     * @author Julio Montoya
325
     * @param integer $id
326
     * @return integer - the question ID
327
     */
328
    public function selectDestination($id)
329
    {
330
        return isset($this->destination[$id]) ? $this->destination[$id] : null;
331
    }
332
333
    /**
334
     * returns the answer title
335
     *
336
     * @author Olivier Brouckaert
337
     * @param - integer $id - answer ID
338
     * @return string - answer title
339
     */
340
    public function selectAnswer($id)
341
    {
342
        return isset($this->answer[$id]) ? $this->answer[$id] : null;
343
    }
344
345
    /**
346
     * return array answer by id else return a bool
347
     * @param integer $auto_id
348
     * @return array
349
     */
350
    public function selectAnswerByAutoId($auto_id)
351
    {
352
        $TBL_ANSWER = Database::get_course_table(TABLE_QUIZ_ANSWER);
353
354
        $auto_id = intval($auto_id);
355
        $sql = "SELECT id, answer, id_auto FROM $TBL_ANSWER
356
                WHERE c_id = {$this->course_id} AND id_auto='$auto_id'";
357
        $rs = Database::query($sql);
358
359
        if (Database::num_rows($rs) > 0) {
360
            $row = Database::fetch_array($rs, 'ASSOC');
361
362
            return $row;
363
        }
364
365
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
366
    }
367
368
    /**
369
     * returns the answer title from an answer's position
370
     *
371
     * @author Yannick Warnier
372
     * @param - integer $id - answer ID
373
     * @return bool - answer title
374
     */
375
    public function selectAnswerIdByPosition($pos)
376
    {
377
        foreach ($this->position as $k => $v) {
378
            if ($v != $pos) {
379
                continue;
380
            }
381
382
            return $k;
383
        }
384
385
        return false;
386
    }
387
388
    /**
389
     * Returns a list of answers
390
     * @author Yannick Warnier <[email protected]>
391
     * @param bool $decode
392
     * @return array    List of answers where each answer is an array
393
     * of (id, answer, comment, grade) and grade=weighting
394
     */
395
    public function getAnswersList($decode = false)
396
    {
397
        $list = [];
398
        for ($i = 1; $i <= $this->nbrAnswers; $i++) {
399
            if (!empty($this->answer[$i])) {
400
                //Avoid problems when parsing elements with accents
401
                if ($decode) {
402
                    $this->answer[$i] = api_html_entity_decode(
403
                        $this->answer[$i],
404
                        ENT_QUOTES,
405
                        api_get_system_encoding()
406
                    );
407
                    $this->comment[$i] = api_html_entity_decode(
408
                        $this->comment[$i],
409
                        ENT_QUOTES,
410
                        api_get_system_encoding()
411
                    );
412
                }
413
414
                $list[] = [
415
                    'id' => $i,
416
                    'answer' => $this->answer[$i],
417
                    'comment' => $this->comment[$i],
418
                    'grade' => $this->weighting[$i],
419
                    'hotspot_coord' => $this->hotspot_coordinates[$i],
420
                    'hotspot_type' => $this->hotspot_type[$i],
421
                    'correct' => $this->correct[$i],
422
                    'destination' => $this->destination[$i],
423
                ];
424
            }
425
        }
426
427
        return $list;
428
    }
429
430
    /**
431
     * Returns a list of grades
432
     * @author Yannick Warnier <[email protected]>
433
     * @return array    List of grades where grade=weighting (?)
434
     */
435
    public function getGradesList()
436
    {
437
        $list = [];
438
        for ($i = 0; $i < $this->nbrAnswers; $i++) {
439
            if (!empty($this->answer[$i])) {
440
                $list[$i] = $this->weighting[$i];
441
            }
442
        }
443
444
        return $list;
445
    }
446
447
    /**
448
     * Returns the question type
449
     * @author    Yannick Warnier <[email protected]>
450
     * @return    integer    The type of the question this answer is bound to
451
     */
452
    public function getQuestionType()
453
    {
454
        $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
455
        $sql = "SELECT type FROM $TBL_QUESTIONS
456
                WHERE c_id = {$this->course_id} AND id = '".$this->questionId."'";
457
        $res = Database::query($sql);
458
        if (Database::num_rows($res) <= 0) {
459
            return null;
460
        }
461
        $row = Database::fetch_array($res);
462
463
        return $row['type'];
464
    }
465
466
467
    /**
468
     * tells if answer is correct or not
469
     *
470
     * @author Olivier Brouckaert
471
     * @param - integer $id - answer ID
472
     * @return integer - 0 if bad answer, not 0 if good answer
473
     */
474
    public function isCorrect($id)
475
    {
476
        return isset($this->correct[$id]) ? $this->correct[$id] : null;
477
    }
478
479
    /**
480
     * returns answer comment
481
     *
482
     * @author Olivier Brouckaert
483
     * @param - integer $id - answer ID
484
     * @return string - answer comment
485
     */
486
    public function selectComment($id)
487
    {
488
        return isset($this->comment[$id]) ? $this->comment[$id] : null;
489
    }
490
491
    /**
492
     * returns answer weighting
493
     *
494
     * @author Olivier Brouckaert
495
     * @param - integer $id - answer ID
496
497
     * @return integer - answer weighting
498
     */
499
    public function selectWeighting($id)
500
    {
501
        return isset($this->weighting[$id]) ? $this->weighting[$id] : null;
502
    }
503
504
    /**
505
     * returns answer position
506
     *
507
     * @author Olivier Brouckaert
508
     * @param - integer $id - answer ID
509
     * @return integer - answer position
510
     */
511
    public function selectPosition($id)
512
    {
513
        return isset($this->position[$id]) ? $this->position[$id] : null;
514
    }
515
516
    /**
517
     * returns answer hotspot coordinates
518
     *
519
     * @author Olivier Brouckaert
520
     * @param integer $id Answer ID
521
     * @return integer    Answer position
522
     */
523
    public function selectHotspotCoordinates($id)
524
    {
525
        return isset($this->hotspot_coordinates[$id]) ? $this->hotspot_coordinates[$id] : null;
526
    }
527
528
    /**
529
     * returns answer hotspot type
530
     *
531
     * @author Toon Keppens
532
     * @param integer $id Answer ID
533
     * @return integer        Answer position
534
     */
535
    public function selectHotspotType($id)
536
    {
537
        return isset($this->hotspot_type[$id]) ? $this->hotspot_type[$id] : null;
538
    }
539
540
    /**
541
     * Creates a new answer
542
     *
543
     * @author Olivier Brouckaert
544
     * @param string $answer answer title
545
     * @param integer $correct 0 if bad answer, not 0 if good answer
546
     * @param string $comment answer comment
547
     * @param integer $weighting answer weighting
548
     * @param integer $position answer position
549
     * @param array $new_hotspot_coordinates Coordinates for hotspot exercises (optional)
550
     * @param integer $new_hotspot_type Type for hotspot exercises (optional)
551
     * @param string $destination
552
     */
553
    public function createAnswer(
554
        $answer,
555
        $correct,
556
        $comment,
557
        $weighting,
558
        $position,
559
        $new_hotspot_coordinates = null,
560
        $new_hotspot_type = null,
561
        $destination = ''
562
    ) {
563
        $this->new_nbrAnswers++;
564
        $id = $this->new_nbrAnswers;
565
        $this->new_answer[$id] = $answer;
566
        $this->new_correct[$id] = $correct;
567
        $this->new_comment[$id] = $comment;
568
        $this->new_weighting[$id] = $weighting;
569
        $this->new_position[$id] = $position;
570
        $this->new_hotspot_coordinates[$id] = $new_hotspot_coordinates;
571
        $this->new_hotspot_type[$id] = $new_hotspot_type;
572
        $this->new_destination[$id] = $destination;
573
    }
574
575
    /**
576
     * Updates an answer
577
     *
578
     * @author Toon Keppens
579
     * @param int $iid
580
     * @param string $answer
581
     * @param string $comment
582
     * @param string $correct
583
     * @param string $weighting
584
     * @param string $position
585
     * @param string $destination
586
     * @param string $hotSpotCoordinates
587
     * @param string $hotSpotType
588
     *
589
     * @return CQuizAnswer
590
     */
591
    public function updateAnswers(
592
        $iid,
593
        $answer,
594
        $comment,
595
        $correct,
596
        $weighting,
597
        $position,
598
        $destination,
599
        $hotSpotCoordinates,
600
        $hotSpotType
601
    ) {
602
        $em = Database::getManager();
603
604
        /** @var CQuizAnswer $quizAnswer */
605
        $quizAnswer = $em->find('ChamiloCourseBundle:CQuizAnswer', $iid);
606
        if ($quizAnswer) {
607
            $quizAnswer
608
                ->setAnswer($answer)
609
                ->setComment($comment)
610
                ->setCorrect($correct)
611
                ->setPonderation($weighting)
612
                ->setPosition($position)
613
                ->setDestination($destination)
614
                ->setHotspotCoordinates($hotSpotCoordinates)
615
                ->setHotspotType($hotSpotType);
616
617
            $em->merge($quizAnswer);
618
            $em->flush();
619
620
            return $quizAnswer;
621
        }
622
623
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type Chamilo\CourseBundle\Entity\CQuizAnswer.
Loading history...
624
    }
625
626
    /**
627
     * Records answers into the data base
628
     *
629
     * @author Olivier Brouckaert
630
     */
631
    public function save()
632
    {
633
        $answerTable = Database::get_course_table(TABLE_QUIZ_ANSWER);
634
        $em = Database::getManager();
635
        $questionId = (int) $this->questionId;
636
637
        $courseId = $this->course['real_id'];
638
        $correctList = [];
639
        $answerList = [];
640
641
        for ($i = 1; $i <= $this->new_nbrAnswers; $i++) {
642
            $answer = $this->new_answer[$i];
643
            $correct = isset($this->new_correct[$i]) ? $this->new_correct[$i] : '';
644
            $comment = isset($this->new_comment[$i]) ? $this->new_comment[$i] : '';
645
            $weighting = isset($this->new_weighting[$i]) ? $this->new_weighting[$i] : '';
646
            $position = isset($this->new_position[$i]) ? $this->new_position[$i] : '';
647
            $hotspot_coordinates = isset($this->new_hotspot_coordinates[$i]) ? $this->new_hotspot_coordinates[$i] : '';
648
            $hotspot_type = isset($this->new_hotspot_type[$i]) ? $this->new_hotspot_type[$i] : '';
649
            $destination = isset($this->new_destination[$i]) ? $this->new_destination[$i] : '';
650
651
            $autoId = $this->selectAutoId($i);
652
            $iid = isset($this->iid[$i]) ? $this->iid[$i] : 0;
653
            $questionType = $this->getQuestionType();
654
655
            if (!isset($this->position[$i])) {
656
                $quizAnswer = new CQuizAnswer();
657
                $quizAnswer
658
                    ->setIdAuto($autoId)
659
                    ->setCId($courseId)
660
                    ->setQuestionId($questionId)
661
                    ->setAnswer($answer)
662
                    ->setCorrect($correct)
0 ignored issues
show
Bug introduced by
It seems like $correct can also be of type string; however, parameter $correct of Chamilo\CourseBundle\Ent...uizAnswer::setCorrect() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

662
                    ->setCorrect(/** @scrutinizer ignore-type */ $correct)
Loading history...
663
                    ->setComment($comment)
664
                    ->setPonderation($weighting)
0 ignored issues
show
Bug introduced by
It seems like $weighting can also be of type string; however, parameter $weight of Chamilo\CourseBundle\Ent...nswer::setPonderation() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

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

664
                    ->setPonderation(/** @scrutinizer ignore-type */ $weighting)
Loading history...
665
                    ->setPosition($position)
0 ignored issues
show
Bug introduced by
It seems like $position can also be of type string; however, parameter $position of Chamilo\CourseBundle\Ent...izAnswer::setPosition() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

665
                    ->setPosition(/** @scrutinizer ignore-type */ $position)
Loading history...
666
                    ->setHotspotCoordinates($hotspot_coordinates)
667
                    ->setHotspotType($hotspot_type)
668
                    ->setDestination($destination);
669
670
                $em->persist($quizAnswer);
671
                $em->flush();
672
673
                $iid = $quizAnswer->getIid();
674
675
676
                if ($iid) {
677
                    $quizAnswer
678
                        ->setId($iid)
679
                        ->setIdAuto($iid);
680
681
                    $em->merge($quizAnswer);
682
                    $em->flush();
683
684
                    if (in_array($questionType, [MATCHING, MATCHING_DRAGGABLE])) {
685
                        $answer = new Answer($this->questionId);
686
                        $answer->read();
687
                        $correctAnswerId = $answer->selectAnswerIdByPosition($correct);
688
689
                        // Continue to avoid matching question bug if $correctAnswerId returns false
690
                        // See : https://support.chamilo.org/issues/8334
691
                        if ($questionType == MATCHING && !$correctAnswerId) {
692
                            continue;
693
                        }
694
695
                        $correctAnswerAutoId = $answer->selectAutoId($correct);
696
                        $quizAnswer->setCorrect($correctAnswerAutoId ? $correctAnswerAutoId : 0);
697
698
                        $em->merge($quizAnswer);
699
                        $em->flush();
700
                    }
701
                }
702
            } else {
703
                // https://support.chamilo.org/issues/6558
704
                // function updateAnswers already escape_string, error if we do it twice.
705
                // Feed function updateAnswers with none escaped strings
706
                $this->updateAnswers(
707
                    $iid,
708
                    $this->new_answer[$i],
709
                    $this->new_comment[$i],
710
                    $this->new_correct[$i],
711
                    $this->new_weighting[$i],
712
                    $this->new_position[$i],
713
                    $this->new_destination[$i],
714
                    $this->new_hotspot_coordinates[$i],
715
                    $this->new_hotspot_type[$i]
716
                );
717
            }
718
719
            $answerList[$i] = $iid;
720
721
            if ($correct) {
722
                $correctList[$iid] = true;
723
            }
724
        }
725
726
        $questionType = self::getQuestionType();
0 ignored issues
show
Bug Best Practice introduced by
The method Answer::getQuestionType() is not static, but was called statically. ( Ignorable by Annotation )

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

726
        /** @scrutinizer ignore-call */ 
727
        $questionType = self::getQuestionType();
Loading history...
727
728
        switch ($questionType) {
729
            case MATCHING_DRAGGABLE:
730
                foreach ($this->new_correct as $value => $status) {
731
                    if (!empty($status)) {
732
                        if (isset($answerList[$status])) {
733
                            $correct = $answerList[$status];
734
                        } else {
735
                            $correct = $status;
736
                        }
737
                        $myAutoId = $answerList[$value];
738
                        $sql = "UPDATE $answerTable
739
                            SET correct = '$correct'
740
                            WHERE
741
                                id_auto = $myAutoId
742
                            ";
743
                        Database::query($sql);
744
                    }
745
                }
746
                break;
747
            case DRAGGABLE:
748
                foreach ($this->new_correct as $value => $status) {
749
                    if (!empty($status)) {
750
                        $correct = $answerList[$status];
751
                        $myAutoId = $answerList[$value];
752
                        $sql = "UPDATE $answerTable
753
                            SET correct = '$correct'
754
                            WHERE
755
                                id_auto = $myAutoId
756
                            ";
757
                        Database::query($sql);
758
                    }
759
                }
760
                break;
761
        }
762
763
        if (count($this->position) > $this->new_nbrAnswers) {
764
            $i = $this->new_nbrAnswers + 1;
765
            while ($this->position[$i]) {
766
                $position = $this->position[$i];
767
                $sql = "DELETE FROM $answerTable
768
                        WHERE
769
                            c_id = {$this->course_id} AND
770
                            question_id = '".$questionId."' AND
771
                            position ='$position'";
772
                Database::query($sql);
773
                $i++;
774
            }
775
        }
776
777
        // moves $new_* arrays
778
        $this->answer = $this->new_answer;
779
        $this->correct = $this->new_correct;
780
        $this->comment = $this->new_comment;
781
        $this->weighting = $this->new_weighting;
782
        $this->position = $this->new_position;
783
        $this->hotspot_coordinates = $this->new_hotspot_coordinates;
784
        $this->hotspot_type = $this->new_hotspot_type;
785
        $this->nbrAnswers = $this->new_nbrAnswers;
786
        $this->destination = $this->new_destination;
787
788
        $this->cancel();
789
    }
790
791
    /**
792
     * Duplicates answers by copying them into another question
793
     *
794
     * @author Olivier Brouckaert
795
     * @param  Question $newQuestion
796
     * @param  array $course_info destination course info (result of the function api_get_course_info() )
797
     */
798
    public function duplicate($newQuestion, $course_info = null)
799
    {
800
        $newQuestionId = $newQuestion->id;
801
802
        if (empty($course_info)) {
803
            $course_info = $this->course;
804
        }
805
806
        $fixed_list = [];
807
        $tableAnswer = Database::get_course_table(TABLE_QUIZ_ANSWER);
808
809
        if (self::getQuestionType() == MULTIPLE_ANSWER_TRUE_FALSE ||
0 ignored issues
show
Bug Best Practice introduced by
The method Answer::getQuestionType() is not static, but was called statically. ( Ignorable by Annotation )

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

809
        if (self::/** @scrutinizer ignore-call */ getQuestionType() == MULTIPLE_ANSWER_TRUE_FALSE ||
Loading history...
810
            self::getQuestionType() == MULTIPLE_ANSWER_TRUE_FALSE
811
        ) {
812
            // Selecting origin options
813
            $origin_options = Question::readQuestionOption(
814
                $this->selectQuestionId(),
815
                $this->course['real_id']
816
            );
817
818
            if (!empty($origin_options)) {
819
                foreach ($origin_options as $item) {
820
                    $new_option_list[] = $item['id'];
821
                }
822
            }
823
824
            $destination_options = Question::readQuestionOption(
825
                $newQuestionId,
826
                $course_info['real_id']
827
            );
828
            $i = 0;
829
            if (!empty($destination_options)) {
830
                foreach ($destination_options as $item) {
831
                    $fixed_list[$new_option_list[$i]] = $item['id'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $new_option_list does not seem to be defined for all execution paths leading up to this point.
Loading history...
832
                    $i++;
833
                }
834
            }
835
        }
836
837
        // if at least one answer
838
        if ($this->nbrAnswers) {
839
            // inserts new answers into data base
840
            $courseId = $course_info['real_id'];
841
            $correctAnswers = [];
842
            $onlyAnswers = [];
843
            $allAnswers = [];
844
845
            $em = Database::getManager();
846
847
            if (in_array($newQuestion->type, [MATCHING, MATCHING_DRAGGABLE])) {
848
                $temp = [];
849
                for ($i = 1; $i <= $this->nbrAnswers; $i++) {
850
                    $answer = [
851
                        'id' => $this->id[$i],
852
                        'answer' => $this->answer[$i],
853
                        'correct' => $this->correct[$i],
854
                        'comment' => $this->comment[$i],
855
                        'weighting' => $this->weighting[$i],
856
                        'ponderation' => $this->weighting[$i],
857
                        'position' => $this->position[$i],
858
                        'hotspot_coordinates' => $this->hotspot_coordinates[$i],
859
                        'hotspot_type' => $this->hotspot_type[$i],
860
                        'destination' => $this->destination[$i],
861
                    ];
862
                    $temp[$answer['position']] = $answer;
863
                    $allAnswers[$this->id[$i]] = $this->answer[$i];
864
                }
865
866
                foreach ($temp as $index => $answer) {
867
                    if ($this->course['id'] != $course_info['id']) {
868
                        // check resources inside html from ckeditor tool and copy correct urls into recipient course
869
                        $answer['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
870
                            $answer['answer'],
871
                            $this->course['id'],
872
                            $course_info['id']
873
                        );
874
875
                        $answer['comment'] = DocumentManager::replaceUrlWithNewCourseCode(
876
                            $answer['comment'],
877
                            $this->course['id'],
878
                            $course_info['id']
879
                        );
880
                    }
881
882
                    $quizAnswer = new CQuizAnswer();
883
                    $quizAnswer
884
                        ->setCId($courseId)
885
                        ->setQuestionId($newQuestionId)
886
                        ->setAnswer($answer['answer'])
887
                        ->setCorrect($answer['correct'])
888
                        ->setComment($answer['comment'])
889
                        ->setPonderation($answer['ponderation'])
890
                        ->setPosition($answer['position'])
891
                        ->setHotspotCoordinates($answer['hotspot_coordinates'])
892
                        ->setHotspotType($answer['hotspot_type'])
893
                        ->setIdAuto(0);
894
895
                    $em->persist($quizAnswer);
896
                    $em->flush();
897
898
                    $answerId = $quizAnswer->getIid();
899
900
                    if ($answerId) {
901
                        $quizAnswer
902
                            ->setId($answerId)
903
                            ->setIdAuto($answerId);
904
905
                        $em->merge($quizAnswer);
906
                        $em->flush();
907
908
                        $correctAnswers[$answerId] = $answer['correct'];
909
                        $onlyAnswers[$answerId] = $answer['answer'];
910
                    }
911
                }
912
            } else {
913
                for ($i = 1; $i <= $this->nbrAnswers; $i++) {
914
                    if ($this->course['id'] != $course_info['id']) {
915
                        $this->answer[$i] = DocumentManager::replaceUrlWithNewCourseCode(
916
                            $this->answer[$i],
917
                            $this->course['id'],
918
                            $course_info['id']
919
                        );
920
                        $this->comment[$i] = DocumentManager::replaceUrlWithNewCourseCode(
921
                            $this->comment[$i],
922
                            $this->course['id'],
923
                            $course_info['id']
924
                        );
925
                    }
926
927
                    $correct = $this->correct[$i];
928
                    if ($newQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE ||
929
                        $newQuestion->type == MULTIPLE_ANSWER_TRUE_FALSE
930
                    ) {
931
                        $correct = $fixed_list[intval($correct)];
932
                    }
933
934
                    $quizAnswer = new CQuizAnswer();
935
                    $quizAnswer
936
                        ->setCId($courseId)
937
                        ->setQuestionId($newQuestionId)
938
                        ->setAnswer($this->answer[$i])
939
                        ->setCorrect($correct)
940
                        ->setComment($this->comment[$i])
941
                        ->setPonderation($this->weighting[$i])
942
                        ->setPosition($this->position[$i])
943
                        ->setHotspotCoordinates($this->hotspot_coordinates[$i])
944
                        ->setHotspotType($this->hotspot_type[$i])
945
                        ->setDestination($this->destination[$i]);
946
947
                    $em->persist($quizAnswer);
948
                    $em->flush();
949
950
                    $answerId = $quizAnswer->getIid();
951
                    $quizAnswer
952
                        ->setId($answerId)
953
                        ->setIdAuto($answerId);
954
955
                    $em->merge($quizAnswer);
956
                    $em->flush();
957
958
                    $correctAnswers[$answerId] = $correct;
959
                    $onlyAnswers[$answerId] = $this->answer[$i];
960
                    $allAnswers[$this->id[$i]] = $this->answer[$i];
961
                }
962
            }
963
964
            // Fix correct answers
965
            if (in_array($newQuestion->type, [DRAGGABLE, MATCHING, MATCHING_DRAGGABLE])) {
966
                $onlyAnswersFlip = array_flip($onlyAnswers);
967
                foreach ($correctAnswers as $answer_id => $correct_answer) {
968
                    $params = [];
969
                    if (isset($allAnswers[$correct_answer]) &&
970
                        isset($onlyAnswersFlip[$allAnswers[$correct_answer]])
971
                    ) {
972
                        $params['correct'] = $onlyAnswersFlip[$allAnswers[$correct_answer]];
973
                        Database::update(
974
                            $tableAnswer,
975
                            $params,
976
                            [
977
                                'id = ? AND c_id = ? AND question_id = ? ' => [
978
                                    $answer_id,
979
                                    $courseId,
980
                                    $newQuestionId,
981
                                ],
982
                            ]
983
                        );
984
                    }
985
                }
986
            }
987
        }
988
    }
989
990
    /**
991
     * Get the necessary JavaScript for some answers
992
     * @return string
993
     */
994
    public function getJs()
995
    {
996
        //if ($this->questionId == 2)
997
        return "<script>
998
                jsPlumb.ready(function() {
999
                    if ($('#drag{$this->questionId}_question').length > 0) {
1000
                        MatchingDraggable.init('{$this->questionId}');
1001
                    }
1002
                });
1003
            </script>";
1004
    }
1005
1006
    /**
1007
     * Check if a answer is correct by an answer auto id
1008
     * @param $needle int The answer auto id
1009
     * @return bool
1010
     */
1011
    public function isCorrectByAutoId($needle)
1012
    {
1013
        $key = 0;
1014
        foreach ($this->autoId as $autoIdKey => $autoId) {
1015
            if ($autoId == $needle) {
1016
                $key = $autoIdKey;
1017
            }
1018
        }
1019
1020
        if (!$key) {
1021
            return false;
1022
        }
1023
1024
        return $this->isCorrect($key) ? true : false;
1025
    }
1026
}
1027