Passed
Push — master ( 78cd0a...f41061 )
by Julito
10:08
created

Evaluation::get_name()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
6
/**
7
 * Class Evaluation.
8
 *
9
 * @package chamilo.gradebook
10
 */
11
class Evaluation implements GradebookItem
12
{
13
    public $studentList;
14
    /** @var \Chamilo\CoreBundle\Entity\GradebookEvaluation */
15
    public $entity;
16
    private $id;
17
    private $name;
18
    private $description;
19
    private $user_id;
20
    private $course_code;
21
    /** @var Category */
22
    private $category;
23
    private $created_at;
24
    private $weight;
25
    private $eval_max;
26
    private $visible;
27
    private $sessionId;
28
29
    /**
30
     * Construct.
31
     */
32
    public function __construct()
33
    {
34
    }
35
36
    /**
37
     * @return Category
38
     */
39
    public function getCategory()
40
    {
41
        return $this->category;
42
    }
43
44
    /**
45
     * @param Category $category
46
     */
47
    public function setCategory($category)
48
    {
49
        $this->category = $category;
50
    }
51
52
    /**
53
     * @return int
54
     */
55
    public function get_category_id()
56
    {
57
        return $this->category->get_id();
58
    }
59
60
    /**
61
     * @param int $category_id
62
     */
63
    public function set_category_id($category_id)
64
    {
65
        $categories = Category::load($category_id);
66
        if (isset($categories[0])) {
67
            $this->setCategory($categories[0]);
68
        }
69
    }
70
71
    /**
72
     * @return int
73
     */
74
    public function get_id()
75
    {
76
        return $this->id;
77
    }
78
79
    /**
80
     * @return string
81
     */
82
    public function get_name()
83
    {
84
        return $this->name;
85
    }
86
87
    /**
88
     * @return string
89
     */
90
    public function get_description()
91
    {
92
        return $this->description;
93
    }
94
95
    public function get_user_id()
96
    {
97
        return $this->user_id;
98
    }
99
100
    public function get_course_code()
101
    {
102
        return $this->course_code;
103
    }
104
105
    /**
106
     * @return int
107
     */
108
    public function getSessionId()
109
    {
110
        return $this->sessionId;
111
    }
112
113
    /**
114
     * @param int $sessionId
115
     */
116
    public function setSessionId($sessionId)
117
    {
118
        $this->sessionId = (int) $sessionId;
119
    }
120
121
    public function get_date()
122
    {
123
        return $this->created_at;
124
    }
125
126
    public function get_weight()
127
    {
128
        return $this->weight;
129
    }
130
131
    public function get_max()
132
    {
133
        return $this->eval_max;
134
    }
135
136
    public function get_type()
137
    {
138
        return $this->type;
139
    }
140
141
    public function is_visible()
142
    {
143
        return $this->visible;
144
    }
145
146
    public function get_locked()
147
    {
148
        return $this->locked;
149
    }
150
151
    public function is_locked()
152
    {
153
        return isset($this->locked) && $this->locked == 1 ? true : false;
154
    }
155
156
    public function set_id($id)
157
    {
158
        $this->id = (int) $id;
159
    }
160
161
    public function set_name($name)
162
    {
163
        $this->name = $name;
164
    }
165
166
    public function set_description($description)
167
    {
168
        $this->description = $description;
169
    }
170
171
    public function set_user_id($user_id)
172
    {
173
        $this->user_id = $user_id;
174
    }
175
176
    public function set_course_code($course_code)
177
    {
178
        $this->course_code = $course_code;
179
    }
180
181
    public function set_date($date)
182
    {
183
        $this->created_at = $date;
184
    }
185
186
    public function set_weight($weight)
187
    {
188
        $this->weight = $weight;
189
    }
190
191
    public function set_max($max)
192
    {
193
        $this->eval_max = $max;
194
    }
195
196
    public function set_visible($visible)
197
    {
198
        $this->visible = $visible;
199
    }
200
201
    public function set_type($type)
202
    {
203
        $this->type = $type;
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
204
    }
205
206
    public function set_locked($locked)
207
    {
208
        $this->locked = $locked;
0 ignored issues
show
Bug Best Practice introduced by
The property locked does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
209
    }
210
211
    /**
212
     * Retrieve evaluations and return them as an array of Evaluation objects.
213
     *
214
     * @param int    $id          evaluation id
215
     * @param int    $user_id     user id (evaluation owner)
216
     * @param string $course_code course code
217
     * @param int    $category_id parent category
218
     * @param int    $visible     visible
219
     *
220
     * @return array
221
     */
222
    public static function load(
223
        $id = null,
224
        $user_id = null,
225
        $course_code = null,
226
        $category_id = null,
227
        $visible = null,
228
        $locked = null
229
    ) {
230
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
231
        $sql = 'SELECT * FROM '.$table;
232
        $paramcount = 0;
233
234
        if (isset($id)) {
235
            $sql .= ' WHERE id = '.intval($id);
236
            $paramcount++;
237
        }
238
239
        if (isset($user_id)) {
240
            if ($paramcount != 0) {
241
                $sql .= ' AND';
242
            } else {
243
                $sql .= ' WHERE';
244
            }
245
            $sql .= ' user_id = '.intval($user_id);
246
            $paramcount++;
247
        }
248
249
        if (isset($course_code) && $course_code != '-1') {
250
            $courseInfo = api_get_course_info($course_code);
251
            if ($courseInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $courseInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
252
                if ($paramcount != 0) {
253
                    $sql .= ' AND';
254
                } else {
255
                    $sql .= ' WHERE';
256
                }
257
                $sql .= " c_id = '".$courseInfo['real_id']."'";
258
                $paramcount++;
259
            }
260
        }
261
262
        if (isset($category_id)) {
263
            if ($paramcount != 0) {
264
                $sql .= ' AND';
265
            } else {
266
                $sql .= ' WHERE';
267
            }
268
            $sql .= ' category_id = '.intval($category_id);
269
            $paramcount++;
270
        }
271
272
        if (isset($visible)) {
273
            if ($paramcount != 0) {
274
                $sql .= ' AND';
275
            } else {
276
                $sql .= ' WHERE';
277
            }
278
            $sql .= ' visible = '.intval($visible);
279
            $paramcount++;
280
        }
281
282
        if (isset($locked)) {
283
            if ($paramcount != 0) {
284
                $sql .= ' AND';
285
            } else {
286
                $sql .= ' WHERE';
287
            }
288
            $sql .= ' locked = '.intval($locked);
289
        }
290
291
        $result = Database::query($sql);
292
        $allEval = self::create_evaluation_objects_from_sql_result($result);
293
294
        return $allEval;
295
    }
296
297
    /**
298
     * Insert this evaluation into the database.
299
     */
300
    public function add()
301
    {
302
        if (isset($this->name) &&
303
            isset($this->user_id) &&
304
            isset($this->weight) &&
305
            isset($this->eval_max) &&
306
            isset($this->visible)
307
        ) {
308
            $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
309
310
            $sql = 'INSERT INTO '.$table
311
                .' (name, user_id, weight, max, visible';
312
            if (isset($this->description)) {
313
                $sql .= ',description';
314
            }
315
            if (isset($this->courseId)) {
316
                $sql .= ', c_id';
317
            }
318
            if (isset($this->category)) {
319
                $sql .= ', category_id';
320
            }
321
            $sql .= ', created_at';
322
            $sql .= ',type';
323
            $sql .= ") VALUES ('".Database::escape_string($this->get_name())."'"
324
                .','.intval($this->get_user_id())
325
                .','.api_float_val($this->get_weight())
326
                .','.intval($this->get_max())
327
                .','.intval($this->is_visible());
328
329
            if (isset($this->description)) {
330
                $sql .= ",'".Database::escape_string($this->get_description())."'";
331
            }
332
            if (isset($this->courseId)) {
333
                $sql .= ",'".Database::escape_string($this->getCourseId())."'";
0 ignored issues
show
Bug introduced by
The method getCourseId() does not exist on Evaluation. ( Ignorable by Annotation )

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

333
                $sql .= ",'".Database::escape_string($this->/** @scrutinizer ignore-call */ getCourseId())."'";

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
334
            }
335
            if (isset($this->category)) {
336
                $sql .= ','.intval($this->get_category_id());
337
            }
338
            if (empty($this->type)) {
339
                $this->type = 'evaluation';
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
340
            }
341
            $sql .= ", '".api_get_utc_datetime()."'";
342
            $sql .= ',\''.Database::escape_string($this->type).'\'';
343
            $sql .= ")";
344
345
            Database::query($sql);
346
            $this->set_id(Database::insert_id());
347
        } else {
348
            return false;
349
            //die('Error in Evaluation add: required field empty');
350
        }
351
    }
352
353
    /**
354
     * @param int $id
355
     */
356
    public function addEvaluationLog($id)
357
    {
358
        if (!empty($id)) {
359
            $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
360
            $tbl_grade_linkeval_log = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINKEVAL_LOG);
361
            $eval = new Evaluation();
362
            $dateobject = $eval->load($id, null, null, null, null);
363
            $arreval = get_object_vars($dateobject[0]);
364
            if (!empty($arreval['id'])) {
365
                $sql = 'SELECT weight from '.$tbl_grade_evaluations.'
366
                        WHERE id='.$arreval['id'];
367
                $rs = Database::query($sql);
368
                $row_old_weight = Database::fetch_array($rs, 'ASSOC');
369
                $current_date = api_get_utc_datetime();
370
                $params = [
371
                    'id_linkeval_log' => $arreval['id'],
372
                    'name' => $arreval['name'],
373
                    'description' => $arreval['description'],
374
                    'created_at' => $current_date,
375
                    'weight' => $row_old_weight['weight'],
376
                    'visible' => $arreval['visible'],
377
                    'type' => 'evaluation',
378
                    'user_id_log' => api_get_user_id(),
379
                ];
380
                Database::insert($tbl_grade_linkeval_log, $params);
381
            }
382
        }
383
    }
384
385
    /**
386
     * Update the properties of this evaluation in the database.
387
     */
388
    public function save()
389
    {
390
        $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
391
        $sql = 'UPDATE '.$tbl_grade_evaluations
392
            ." SET name = '".Database::escape_string($this->get_name())."'"
393
            .', description = ';
394
        if (isset($this->description)) {
395
            $sql .= "'".Database::escape_string($this->get_description())."'";
396
        } else {
397
            $sql .= 'null';
398
        }
399
        $sql .= ', user_id = '.intval($this->get_user_id())
400
            .', c_id = ';
401
        if (isset($this->courseId)) {
402
            $sql .= "'".Database::escape_string($this->getCourseId())."'";
403
        } else {
404
            $sql .= 'null';
405
        }
406
        $sql .= ', category_id = ';
407
        if (isset($this->category)) {
408
            $sql .= intval($this->get_category_id());
409
        } else {
410
            $sql .= 'null';
411
        }
412
        $sql .= ', weight = "'.Database::escape_string($this->get_weight()).'" '
413
            .', max = '.intval($this->get_max())
414
            .', visible = '.intval($this->is_visible())
415
            .' WHERE id = '.intval($this->id);
416
        //recorded history
417
418
        $eval_log = new Evaluation();
419
        $eval_log->addEvaluationLog($this->id);
420
        Database::query($sql);
421
    }
422
423
    /**
424
     * Delete this evaluation from the database.
425
     */
426
    public function delete()
427
    {
428
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
429
        $sql = 'DELETE FROM '.$table.' 
430
                WHERE id = '.intval($this->id);
431
        Database::query($sql);
432
    }
433
434
    /**
435
     * Check if an evaluation name (with the same parent category) already exists.
436
     *
437
     * @param string $name to check (if not given, the name property of this object will be checked)
438
     * @param $parent parent category
439
     *
440
     * @return bool
441
     */
442
    public function does_name_exist($name, $parent)
443
    {
444
        if (!isset($name)) {
445
            $name = $this->name;
446
            $parent = $this->category;
447
        }
448
        $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
449
        $sql = "SELECT count(id) AS number 
450
                FROM $tbl_grade_evaluations 
451
                WHERE name = '".Database::escape_string($name)."'";
452
453
        if (api_is_allowed_to_edit()) {
454
            $parent = Category::load($parent);
455
            $courseId = $parent[0]->getCourseId();
456
            if (isset($courseId) && !empty($courseId)) {
457
                $table = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
458
                $sql .= ' AND user_id IN (
459
					 SELECT user_id FROM '.$table.'
460
					 WHERE
461
						c_id = '.$courseId.' AND
462
						status = '.COURSEMANAGER.'
463
					)';
464
            } else {
465
                $sql .= ' AND user_id = '.api_get_user_id();
466
            }
467
        } else {
468
            $sql .= ' AND user_id = '.api_get_user_id();
469
        }
470
471
        if (!isset($parent)) {
472
            $sql .= ' AND category_id is null';
473
        } else {
474
            $sql .= ' AND category_id = '.intval($parent);
475
        }
476
        $result = Database::query($sql);
477
        $number = Database::fetch_row($result);
478
479
        return $number[0] != 0;
480
    }
481
482
    /**
483
     * Are there any results for this evaluation yet ?
484
     * The 'max' property should not be changed then.
485
     *
486
     * @return bool
487
     */
488
    public function has_results()
489
    {
490
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
491
        $sql = 'SELECT count(id) AS number
492
                FROM '.$table.'
493
                WHERE evaluation_id = '.intval($this->id);
494
        $result = Database::query($sql);
495
        $number = Database::fetch_row($result);
496
497
        return $number[0] != 0;
498
    }
499
500
    /**
501
     * Delete all results for this evaluation.
502
     */
503
    public function delete_results()
504
    {
505
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
506
        $sql = 'DELETE FROM '.$table.'
507
                WHERE evaluation_id = '.intval($this->id);
508
        Database::query($sql);
509
    }
510
511
    /**
512
     * Delete this evaluation and all underlying results.
513
     */
514
    public function delete_with_results()
515
    {
516
        $this->delete_results();
517
        $this->delete();
518
    }
519
520
    /**
521
     * Check if the given score is possible for this evaluation.
522
     */
523
    public function is_valid_score($score)
524
    {
525
        return is_numeric($score) && $score >= 0 && $score <= $this->eval_max;
526
    }
527
528
    /**
529
     * Calculate the score of this evaluation.
530
     *
531
     * @param int    $stud_id (default: all students who have results for this eval - then the average is returned)
532
     * @param string $type    (best, average, ranking)
533
     *
534
     * @return array (score, max) if student is given
535
     *               array (sum of scores, number of scores) otherwise
536
     *               or null if no scores available
537
     */
538
    public function calc_score($stud_id = null, $type = null)
539
    {
540
        $allowStats = api_get_configuration_value('allow_gradebook_stats');
541
        if ($allowStats) {
542
            $evaluation = $this->entity;
543
            if (!empty($evaluation)) {
544
                $weight = $evaluation->getMax();
545
                switch ($type) {
546
                    case 'best':
547
                        $bestResult = $evaluation->getBestScore();
0 ignored issues
show
Bug introduced by
The method getBestScore() does not exist on Chamilo\CoreBundle\Entity\GradebookEvaluation. ( Ignorable by Annotation )

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

547
                        /** @scrutinizer ignore-call */ 
548
                        $bestResult = $evaluation->getBestScore();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
548
                        $result = [$bestResult, $weight];
549
550
                        return $result;
551
                        break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
552
                    case 'average':
553
                        $count = count($evaluation->getUserScoreList());
0 ignored issues
show
Bug introduced by
The method getUserScoreList() does not exist on Chamilo\CoreBundle\Entity\GradebookEvaluation. ( Ignorable by Annotation )

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

553
                        $count = count($evaluation->/** @scrutinizer ignore-call */ getUserScoreList());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
554
                        if (empty($count)) {
555
                            $result = [0, $weight];
556
557
                            return $result;
558
                        }
559
560
                        $sumResult = array_sum($evaluation->getUserScoreList());
561
                        $result = [$sumResult / $count, $weight];
562
563
                        return $result;
564
                        break;
565
                    case 'ranking':
566
                        $ranking = AbstractLink::getCurrentUserRanking($stud_id, $evaluation->getUserScoreList());
567
568
                        return $ranking;
569
                        break;
570
                    default:
571
                        $weight = $evaluation->getMax();
572
                        if (!empty($stud_id)) {
573
                            $scoreList = $evaluation->getUserScoreList();
574
                            $result = [0, $weight];
575
                            if (isset($scoreList[$stud_id])) {
576
                                $result = [$scoreList[$stud_id], $weight];
577
                            }
578
579
                            return $result;
580
                        } else {
581
                            $studentCount = count($evaluation->getUserScoreList());
582
                            $sumResult = array_sum($evaluation->getUserScoreList());
583
                            $result = [$sumResult, $studentCount];
584
                        }
585
586
                        return $result;
587
                        break;
588
                }
589
            }
590
        }
591
592
        $useSession = true;
593
        if (isset($stud_id) && empty($type)) {
594
            $key = 'result_score_student_list_'.api_get_course_int_id().'_'.api_get_session_id().'_'.$this->id.'_'.$stud_id;
595
            $data = Session::read('calc_score');
596
            $results = isset($data[$key]) ? $data[$key] : null;
597
598
            if ($useSession == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
599
                $results = null;
600
            }
601
            $results = null;
602
            if (empty($results)) {
603
                $results = Result::load(null, $stud_id, $this->id);
604
                Session::write('calc_score', [$key => $results]);
605
            }
606
607
            $score = 0;
608
            /** @var Result $res */
609
            foreach ($results as $res) {
610
                $score = $res->get_score();
611
            }
612
613
            return [$score, $this->get_max()];
614
        } else {
615
            $count = 0;
616
            $sum = 0;
617
            $bestResult = 0;
618
            $weight = 0;
619
            $sumResult = 0;
620
621
            $key = 'result_score_student_list_'.api_get_course_int_id().'_'.api_get_session_id().'_'.$this->id;
622
            $data = Session::read('calc_score');
623
            $allResults = isset($data[$key]) ? $data[$key] : null;
624
            if ($useSession == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
625
                $allResults = null;
626
            }
627
628
            if (empty($allResults)) {
629
                $allResults = Result::load(null, null, $this->id);
630
                Session::write($key, $allResults);
631
            }
632
633
            $students = [];
634
            /** @var Result $res */
635
            foreach ($allResults as $res) {
636
                $score = $res->get_score();
637
                if (!empty($score) || $score == '0') {
638
                    $count++;
639
                    $sum += $score / $this->get_max();
640
                    $sumResult += $score;
641
                    if ($score > $bestResult) {
642
                        $bestResult = $score;
643
                    }
644
                    $weight = $this->get_max();
645
                }
646
                $students[$res->get_user_id()] = $score;
647
            }
648
            if (empty($count)) {
649
                return null;
650
            }
651
652
            switch ($type) {
653
                case 'best':
654
                    return [$bestResult, $weight];
655
                    break;
656
                case 'average':
657
                    return [$sumResult / $count, $weight];
658
                    break;
659
                case 'ranking':
660
                    $students = [];
661
                    /** @var Result $res */
662
                    foreach ($allResults as $res) {
663
                        $score = $res->get_score();
664
                        $students[$res->get_user_id()] = $score;
665
                    }
666
667
                    return AbstractLink::getCurrentUserRanking($stud_id, $students);
668
                    break;
669
                default:
670
                    return [$sum, $count];
671
                    break;
672
            }
673
        }
674
    }
675
676
    /**
677
     * Generate an array of possible categories where this evaluation can be moved to.
678
     * Notice: its own parent will be included in the list: it's up to the frontend
679
     * to disable this element.
680
     *
681
     * @return array 2-dimensional array - every element contains 3 subelements (id, name, level)
682
     */
683
    public function get_target_categories()
684
    {
685
        // - course independent evaluation
686
        //   -> movable to root or other course independent categories
687
        // - evaluation inside a course
688
        //   -> movable to root, independent categories or categories inside the course
689
        $user = api_is_platform_admin() ? null : api_get_user_id();
690
        $targets = [];
691
        $level = 0;
692
        $root = [0, get_lang('RootCat'), $level];
693
        $targets[] = $root;
694
695
        if (isset($this->courseId) && !empty($this->courseId)) {
696
            $crscats = Category::load(null, null, $this->course_code, 0);
697
            foreach ($crscats as $cat) {
698
                $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
699
                $targets = $this->addTargetSubcategories($targets, $level + 1, $cat->get_id());
700
            }
701
        }
702
703
        $indcats = Category::load(null, $user, 0, 0);
704
        foreach ($indcats as $cat) {
705
            $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
706
            $targets = $this->addTargetSubcategories(
707
                $targets,
708
                $level + 1,
709
                $cat->get_id()
710
            );
711
        }
712
713
        return $targets;
714
    }
715
716
    /**
717
     * Move this evaluation to the given category.
718
     * If this evaluation moves from inside a course to outside,
719
     * its course code is also changed.
720
     */
721
    public function move_to_cat($cat)
722
    {
723
        $this->set_category_id($cat->get_id());
724
        if ($this->get_course_code() != $cat->get_course_code()) {
725
            $this->set_course_code($cat->get_course_code());
726
        }
727
        $this->save();
728
    }
729
730
    /**
731
     * Retrieve evaluations where a student has results for
732
     * and return them as an array of Evaluation objects.
733
     *
734
     * @param int $cat_id  parent category (use 'null' to retrieve them in all categories)
735
     * @param int $stud_id student id
736
     *
737
     * @return array
738
     */
739
    public static function get_evaluations_with_result_for_student($cat_id = null, $stud_id)
740
    {
741
        $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
742
        $tbl_grade_results = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
743
744
        $sql = 'SELECT * FROM '.$tbl_grade_evaluations.'
745
                WHERE id IN (
746
                    SELECT evaluation_id FROM '.$tbl_grade_results.'
747
                    WHERE user_id = '.intval($stud_id).' AND score IS NOT NULL
748
                )';
749
        if (!api_is_allowed_to_edit()) {
750
            $sql .= ' AND visible = 1';
751
        }
752
        if (isset($cat_id)) {
753
            $sql .= ' AND category_id = '.intval($cat_id);
754
        } else {
755
            $sql .= ' AND category_id >= 0';
756
        }
757
758
        $result = Database::query($sql);
759
        $alleval = self::create_evaluation_objects_from_sql_result($result);
760
761
        return $alleval;
762
    }
763
764
    /**
765
     * Get a list of students that do not have a result record for this evaluation.
766
     *
767
     * @param string $first_letter_user
768
     *
769
     * @return array
770
     */
771
    public function get_not_subscribed_students($first_letter_user = '')
772
    {
773
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
774
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
775
776
        $sql = "SELECT user_id,lastname,firstname,username 
777
                FROM $tbl_user 
778
                WHERE 
779
                    lastname LIKE '".Database::escape_string($first_letter_user)."%' AND 
780
                    status = ".STUDENT." AND user_id NOT IN (
781
                        SELECT user_id FROM $table 
782
                        WHERE evaluation_id = ".intval($this->id)."
783
                    )
784
                ORDER BY lastname";
785
786
        $result = Database::query($sql);
787
        $users = Database::store_result($result);
788
789
        return $users;
790
    }
791
792
    /**
793
     * Find evaluations by name.
794
     *
795
     * @param string $name_mask search string
796
     *
797
     * @return array evaluation objects matching the search criterium
798
     *
799
     * @todo can be written more efficiently using a new (but very complex) sql query
800
     */
801
    public function findEvaluations($name_mask, $selectcat)
802
    {
803
        $rootcat = Category::load($selectcat);
804
        $evals = $rootcat[0]->get_evaluations(
805
            (api_is_allowed_to_create_course() ? null : api_get_user_id()),
806
            true
807
        );
808
        $foundevals = [];
809
        foreach ($evals as $eval) {
810
            if (!(api_strpos(api_strtolower($eval->get_name()), api_strtolower($name_mask)) === false)) {
811
                $foundevals[] = $eval;
812
            }
813
        }
814
815
        return $foundevals;
816
    }
817
818
    public function get_item_type()
819
    {
820
        return 'E';
821
    }
822
823
    public function get_icon_name()
824
    {
825
        return $this->has_results() ? 'evalnotempty' : 'evalempty';
826
    }
827
828
    /**
829
     * Locks an evaluation, only one who can unlock it is the platform administrator.
830
     *
831
     * @param int locked 1 or unlocked 0
832
     */
833
    public function lock($locked)
834
    {
835
        $table_evaluation = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
836
        $sql = "UPDATE $table_evaluation 
837
                SET locked = '".intval($locked)."' 
838
                WHERE id='".intval($this->id)."'";
839
        Database::query($sql);
840
    }
841
842
    public function check_lock_permissions()
843
    {
844
        if (api_is_platform_admin()) {
845
            return true;
846
        } else {
847
            if ($this->is_locked()) {
848
                api_not_allowed();
849
            }
850
        }
851
    }
852
853
    public function delete_linked_data()
854
    {
855
    }
856
857
    /**
858
     * @return mixed
859
     */
860
    public function getStudentList()
861
    {
862
        return $this->studentList;
863
    }
864
865
    /**
866
     * @param $list
867
     */
868
    public function setStudentList($list)
869
    {
870
        $this->studentList = $list;
871
    }
872
873
    /**
874
     * @param int $evaluationId
875
     */
876
    public static function generateStats($evaluationId)
877
    {
878
        $allowStats = api_get_configuration_value('allow_gradebook_stats');
879
        if ($allowStats) {
880
            $evaluation = self::load($evaluationId);
881
882
            $results = Result::load(null, null, $evaluationId);
883
            $sumResult = 0;
884
            $bestResult = 0;
885
            $average = 0;
886
            $scoreList = [];
887
888
            if (!empty($results)) {
889
                /** @var Result $result */
890
                foreach ($results as $result) {
891
                    $score = $result->get_score();
892
                    $scoreList[$result->get_user_id()] = $score;
893
                    $sumResult += $score;
894
                    if ($score > $bestResult) {
895
                        $bestResult = $score;
896
                    }
897
                }
898
                $average = $sumResult / count($results);
899
            }
900
901
            /** @var Evaluation $evaluation */
902
            $evaluation = $evaluation[0];
903
            $evaluation = $evaluation->entity;
904
            $evaluation
905
                ->setBestScore($bestResult)
0 ignored issues
show
Bug introduced by
The method setBestScore() does not exist on Chamilo\CoreBundle\Entity\GradebookEvaluation. ( Ignorable by Annotation )

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

905
                ->/** @scrutinizer ignore-call */ 
906
                  setBestScore($bestResult)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
906
                ->setAverageScore($average)
907
                ->setUserScoreList($scoreList)
908
            ;
909
910
            $em = Database::getManager();
911
            $em->persist($evaluation);
912
            $em->flush();
913
        }
914
    }
915
916
    /**
917
     * @param int $courseId
918
     *
919
     * @return Evaluation
920
     */
921
    public function setCourseId($courseId)
922
    {
923
        $this->courseId = $courseId;
0 ignored issues
show
Bug Best Practice introduced by
The property courseId does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
924
925
        return $this;
926
    }
927
928
    /**
929
     * @param array $result
930
     *
931
     * @return array
932
     */
933
    private static function create_evaluation_objects_from_sql_result($result)
934
    {
935
        $alleval = [];
936
        $allow = api_get_configuration_value('allow_gradebook_stats');
937
        if ($allow) {
938
            $em = Database::getManager();
939
            $repo = $em->getRepository('ChamiloCoreBundle:GradebookEvaluation');
940
        }
941
942
        if (Database::num_rows($result)) {
943
            while ($data = Database::fetch_array($result)) {
944
                $eval = new Evaluation();
945
                $eval->set_id($data['id']);
946
                $eval->set_name($data['name']);
947
                $eval->set_description($data['description']);
948
                $eval->set_user_id($data['user_id']);
949
                $eval->setCourseId($data['c_id']);
950
                $courseInfo = api_get_course_info_by_id($data['c_id']);
951
                $eval->set_course_code($courseInfo['code']);
952
                $eval->set_category_id($data['category_id']);
953
                $eval->set_date(api_get_local_time($data['created_at']));
954
                $eval->set_weight($data['weight']);
955
                $eval->set_max($data['max']);
956
                $eval->set_visible($data['visible']);
957
                $eval->set_type($data['type']);
958
                $eval->set_locked($data['locked']);
959
                $eval->setSessionId(api_get_session_id());
960
961
                if ($allow) {
962
                    $eval->entity = $repo->find($data['id']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $repo does not seem to be defined for all execution paths leading up to this point.
Loading history...
963
                }
964
965
                $alleval[] = $eval;
966
            }
967
        }
968
969
        return $alleval;
970
    }
971
972
    /**
973
     * Internal function used by get_target_categories().
974
     *
975
     * @param int $level
976
     *
977
     * @return array
978
     */
979
    private function addTargetSubcategories($targets, $level, $catid)
980
    {
981
        $subcats = Category::load(null, null, null, $catid);
982
        foreach ($subcats as $cat) {
983
            $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
984
            $targets = $this->addTargetSubcategories(
985
                $targets,
986
                $level + 1,
987
                $cat->get_id()
988
            );
989
        }
990
991
        return $targets;
992
    }
993
}
994