Completed
Push — master ( 0d55cd...2b4dde )
by Julito
09:59
created

Evaluation::add()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 31
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 23
nc 3
nop 0
dl 0
loc 31
rs 8.6186
c 1
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
use Chamilo\CoreBundle\Entity\GradebookEvaluation;
6
7
/**
8
 * Class Evaluation.
9
 *
10
 * @package chamilo.gradebook
11
 */
12
class Evaluation implements GradebookItem
13
{
14
    public $studentList;
15
    /** @var GradebookEvaluation */
16
    public $entity;
17
    private $id;
18
    private $name;
19
    private $description;
20
    private $user_id;
21
    private $course_code;
22
    /** @var Category */
23
    private $category;
24
    private $created_at;
25
    private $weight;
26
    private $eval_max;
27
    private $visible;
28
    private $sessionId;
29
30
    /**
31
     * Construct.
32
     */
33
    public function __construct()
34
    {
35
    }
36
37
    /**
38
     * @return Category
39
     */
40
    public function getCategory()
41
    {
42
        return $this->category;
43
    }
44
45
    /**
46
     * @param Category $category
47
     */
48
    public function setCategory($category)
49
    {
50
        $this->category = $category;
51
    }
52
53
    /**
54
     * @return int
55
     */
56
    public function get_category_id()
57
    {
58
        return $this->category->get_id();
59
    }
60
61
    /**
62
     * @param int $category_id
63
     */
64
    public function set_category_id($category_id)
65
    {
66
        $categories = Category::load($category_id);
67
        if (isset($categories[0])) {
68
            $this->setCategory($categories[0]);
69
        }
70
    }
71
72
    /**
73
     * @return int
74
     */
75
    public function get_id()
76
    {
77
        return $this->id;
78
    }
79
80
    /**
81
     * @return string
82
     */
83
    public function get_name()
84
    {
85
        return $this->name;
86
    }
87
88
    /**
89
     * @return string
90
     */
91
    public function get_description()
92
    {
93
        return $this->description;
94
    }
95
96
    public function get_user_id()
97
    {
98
        return $this->user_id;
99
    }
100
101
    public function get_course_code()
102
    {
103
        return $this->course_code;
104
    }
105
106
    /**
107
     * @return int
108
     */
109
    public function getSessionId()
110
    {
111
        return $this->sessionId;
112
    }
113
114
    /**
115
     * @param int $sessionId
116
     */
117
    public function setSessionId($sessionId)
118
    {
119
        $this->sessionId = (int) $sessionId;
120
    }
121
122
    public function get_date()
123
    {
124
        return $this->created_at;
125
    }
126
127
    public function get_weight()
128
    {
129
        return $this->weight;
130
    }
131
132
    public function get_max()
133
    {
134
        return $this->eval_max;
135
    }
136
137
    public function get_type()
138
    {
139
        return $this->type;
140
    }
141
142
    public function is_visible()
143
    {
144
        return $this->visible;
145
    }
146
147
    public function get_locked()
148
    {
149
        return $this->locked;
150
    }
151
152
    public function is_locked()
153
    {
154
        return isset($this->locked) && $this->locked == 1 ? true : false;
155
    }
156
157
    public function set_id($id)
158
    {
159
        $this->id = (int) $id;
160
    }
161
162
    public function set_name($name)
163
    {
164
        $this->name = $name;
165
    }
166
167
    public function set_description($description)
168
    {
169
        $this->description = $description;
170
    }
171
172
    public function set_user_id($user_id)
173
    {
174
        $this->user_id = $user_id;
175
    }
176
177
    public function set_course_code($course_code)
178
    {
179
        $this->course_code = $course_code;
180
    }
181
182
    public function set_date($date)
183
    {
184
        $this->created_at = $date;
185
    }
186
187
    public function set_weight($weight)
188
    {
189
        $this->weight = $weight;
190
    }
191
192
    public function set_max($max)
193
    {
194
        $this->eval_max = $max;
195
    }
196
197
    public function set_visible($visible)
198
    {
199
        $this->visible = $visible;
200
    }
201
202
    public function set_type($type)
203
    {
204
        $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...
205
    }
206
207
    public function set_locked($locked)
208
    {
209
        $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...
210
    }
211
212
    /**
213
     * Retrieve evaluations and return them as an array of Evaluation objects.
214
     *
215
     * @param int    $id          evaluation id
216
     * @param int    $user_id     user id (evaluation owner)
217
     * @param string $course_code course code
218
     * @param int    $category_id parent category
219
     * @param int    $visible     visible
220
     *
221
     * @return array
222
     */
223
    public static function load(
224
        $id = null,
225
        $user_id = null,
226
        $course_code = null,
227
        $category_id = null,
228
        $visible = null,
229
        $locked = null
230
    ) {
231
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
232
        $sql = 'SELECT * FROM '.$table;
233
        $paramcount = 0;
234
235
        if (isset($id)) {
236
            $sql .= ' WHERE id = '.intval($id);
237
            $paramcount++;
238
        }
239
240
        if (isset($user_id)) {
241
            if ($paramcount != 0) {
242
                $sql .= ' AND';
243
            } else {
244
                $sql .= ' WHERE';
245
            }
246
            $sql .= ' user_id = '.intval($user_id);
247
            $paramcount++;
248
        }
249
250
        if (isset($course_code) && $course_code != '-1') {
251
            $courseInfo = api_get_course_info($course_code);
252
            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...
253
                if ($paramcount != 0) {
254
                    $sql .= ' AND';
255
                } else {
256
                    $sql .= ' WHERE';
257
                }
258
                $sql .= " c_id = '".$courseInfo['real_id']."'";
259
                $paramcount++;
260
            }
261
        }
262
263
        if (isset($category_id)) {
264
            if ($paramcount != 0) {
265
                $sql .= ' AND';
266
            } else {
267
                $sql .= ' WHERE';
268
            }
269
            $sql .= ' category_id = '.intval($category_id);
270
            $paramcount++;
271
        }
272
273
        if (isset($visible)) {
274
            if ($paramcount != 0) {
275
                $sql .= ' AND';
276
            } else {
277
                $sql .= ' WHERE';
278
            }
279
            $sql .= ' visible = '.intval($visible);
280
            $paramcount++;
281
        }
282
283
        if (isset($locked)) {
284
            if ($paramcount != 0) {
285
                $sql .= ' AND';
286
            } else {
287
                $sql .= ' WHERE';
288
            }
289
            $sql .= ' locked = '.intval($locked);
290
        }
291
292
        $result = Database::query($sql);
293
        $allEval = self::create_evaluation_objects_from_sql_result($result);
294
295
        return $allEval;
296
    }
297
298
    /**
299
     * Insert this evaluation into the database.
300
     */
301
    public function add()
302
    {
303
        if (isset($this->name) &&
304
            isset($this->user_id) &&
305
            isset($this->weight) &&
306
            isset($this->eval_max) &&
307
            isset($this->visible)
308
        ) {
309
            if (empty($this->type)) {
310
                $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...
311
            }
312
            $em = Database::getManager();
313
314
            $evaluation = new GradebookEvaluation();
315
            $evaluation
316
                ->setDescription($this->description)
317
                ->setCourse(api_get_course_entity())
318
                ->setName($this->get_name())
319
                ->setCategoryId($this->get_category_id())
320
                ->setUserId($this->get_user_id())
321
                ->setWeight(api_float_val($this->get_weight()))
322
                ->setMax($this->get_max())
323
                ->setVisible($this->is_visible())
324
                ->setType($this->type)
325
            ;
326
            $em->persist($evaluation);
327
            $em->flush();
328
            $this->set_id($evaluation->getId());
329
        }
330
331
        return false;
332
    }
333
334
    /**
335
     * @param int $id
336
     */
337
    public function addEvaluationLog($id)
338
    {
339
        if (!empty($id)) {
340
            $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
341
            $tbl_grade_linkeval_log = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINKEVAL_LOG);
342
            $eval = new Evaluation();
343
            $dateobject = $eval->load($id, null, null, null, null);
344
            $arreval = get_object_vars($dateobject[0]);
345
            if (!empty($arreval['id'])) {
346
                $sql = 'SELECT weight from '.$tbl_grade_evaluations.'
347
                        WHERE id='.$arreval['id'];
348
                $rs = Database::query($sql);
349
                $row_old_weight = Database::fetch_array($rs, 'ASSOC');
350
                $current_date = api_get_utc_datetime();
351
                $params = [
352
                    'id_linkeval_log' => $arreval['id'],
353
                    'name' => $arreval['name'],
354
                    'description' => $arreval['description'],
355
                    'created_at' => $current_date,
356
                    'weight' => $row_old_weight['weight'],
357
                    'visible' => $arreval['visible'],
358
                    'type' => 'evaluation',
359
                    'user_id_log' => api_get_user_id(),
360
                ];
361
                Database::insert($tbl_grade_linkeval_log, $params);
362
            }
363
        }
364
    }
365
366
    /**
367
     * Update the properties of this evaluation in the database.
368
     */
369
    public function save()
370
    {
371
        $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
372
        $sql = 'UPDATE '.$tbl_grade_evaluations
373
            ." SET name = '".Database::escape_string($this->get_name())."'"
374
            .', description = ';
375
        if (isset($this->description)) {
376
            $sql .= "'".Database::escape_string($this->get_description())."'";
377
        } else {
378
            $sql .= 'null';
379
        }
380
        $sql .= ', user_id = '.intval($this->get_user_id())
381
            .', c_id = ';
382
        if (isset($this->courseId)) {
383
            $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

383
            $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...
384
        } else {
385
            $sql .= 'null';
386
        }
387
        $sql .= ', category_id = ';
388
        if (isset($this->category)) {
389
            $sql .= intval($this->get_category_id());
390
        } else {
391
            $sql .= 'null';
392
        }
393
        $sql .= ', weight = "'.Database::escape_string($this->get_weight()).'" '
394
            .', max = '.intval($this->get_max())
395
            .', visible = '.intval($this->is_visible())
396
            .' WHERE id = '.intval($this->id);
397
        //recorded history
398
399
        $eval_log = new Evaluation();
400
        $eval_log->addEvaluationLog($this->id);
401
        Database::query($sql);
402
    }
403
404
    /**
405
     * Delete this evaluation from the database.
406
     */
407
    public function delete()
408
    {
409
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
410
        $sql = 'DELETE FROM '.$table.' 
411
                WHERE id = '.intval($this->id);
412
        Database::query($sql);
413
    }
414
415
    /**
416
     * Check if an evaluation name (with the same parent category) already exists.
417
     *
418
     * @param string $name to check (if not given, the name property of this object will be checked)
419
     * @param $parent parent category
420
     *
421
     * @return bool
422
     */
423
    public function does_name_exist($name, $parent)
424
    {
425
        if (!isset($name)) {
426
            $name = $this->name;
427
            $parent = $this->category;
428
        }
429
        $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
430
        $sql = "SELECT count(id) AS number 
431
                FROM $tbl_grade_evaluations 
432
                WHERE name = '".Database::escape_string($name)."'";
433
434
        if (api_is_allowed_to_edit()) {
435
            $parent = Category::load($parent);
436
            $courseId = $parent[0]->getCourseId();
437
            if (isset($courseId) && !empty($courseId)) {
438
                $table = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
439
                $sql .= ' AND user_id IN (
440
					 SELECT user_id FROM '.$table.'
441
					 WHERE
442
						c_id = '.$courseId.' AND
443
						status = '.COURSEMANAGER.'
444
					)';
445
            } else {
446
                $sql .= ' AND user_id = '.api_get_user_id();
447
            }
448
        } else {
449
            $sql .= ' AND user_id = '.api_get_user_id();
450
        }
451
452
        if (!isset($parent)) {
453
            $sql .= ' AND category_id is null';
454
        } else {
455
            $sql .= ' AND category_id = '.intval($parent);
456
        }
457
        $result = Database::query($sql);
458
        $number = Database::fetch_row($result);
459
460
        return $number[0] != 0;
461
    }
462
463
    /**
464
     * Are there any results for this evaluation yet ?
465
     * The 'max' property should not be changed then.
466
     *
467
     * @return bool
468
     */
469
    public function has_results()
470
    {
471
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
472
        $sql = 'SELECT count(id) AS number
473
                FROM '.$table.'
474
                WHERE evaluation_id = '.intval($this->id);
475
        $result = Database::query($sql);
476
        $number = Database::fetch_row($result);
477
478
        return $number[0] != 0;
479
    }
480
481
    /**
482
     * Delete all results for this evaluation.
483
     */
484
    public function delete_results()
485
    {
486
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
487
        $sql = 'DELETE FROM '.$table.'
488
                WHERE evaluation_id = '.intval($this->id);
489
        Database::query($sql);
490
    }
491
492
    /**
493
     * Delete this evaluation and all underlying results.
494
     */
495
    public function delete_with_results()
496
    {
497
        $this->delete_results();
498
        $this->delete();
499
    }
500
501
    /**
502
     * Check if the given score is possible for this evaluation.
503
     */
504
    public function is_valid_score($score)
505
    {
506
        return is_numeric($score) && $score >= 0 && $score <= $this->eval_max;
507
    }
508
509
    /**
510
     * Calculate the score of this evaluation.
511
     *
512
     * @param int    $stud_id (default: all students who have results for this eval - then the average is returned)
513
     * @param string $type    (best, average, ranking)
514
     *
515
     * @return array (score, max) if student is given
516
     *               array (sum of scores, number of scores) otherwise
517
     *               or null if no scores available
518
     */
519
    public function calc_score($stud_id = null, $type = null)
520
    {
521
        $allowStats = api_get_configuration_value('allow_gradebook_stats');
522
        if ($allowStats) {
523
            $evaluation = $this->entity;
524
            if (!empty($evaluation)) {
525
                $weight = $evaluation->getMax();
526
                switch ($type) {
527
                    case 'best':
528
                        $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

528
                        /** @scrutinizer ignore-call */ 
529
                        $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...
529
                        $result = [$bestResult, $weight];
530
531
                        return $result;
532
                        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...
533
                    case 'average':
534
                        $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

534
                        $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...
535
                        if (empty($count)) {
536
                            $result = [0, $weight];
537
538
                            return $result;
539
                        }
540
541
                        $sumResult = array_sum($evaluation->getUserScoreList());
542
                        $result = [$sumResult / $count, $weight];
543
544
                        return $result;
545
                        break;
546
                    case 'ranking':
547
                        $ranking = AbstractLink::getCurrentUserRanking($stud_id, $evaluation->getUserScoreList());
548
549
                        return $ranking;
550
                        break;
551
                    default:
552
                        $weight = $evaluation->getMax();
553
                        if (!empty($stud_id)) {
554
                            $scoreList = $evaluation->getUserScoreList();
555
                            $result = [0, $weight];
556
                            if (isset($scoreList[$stud_id])) {
557
                                $result = [$scoreList[$stud_id], $weight];
558
                            }
559
560
                            return $result;
561
                        } else {
562
                            $studentCount = count($evaluation->getUserScoreList());
563
                            $sumResult = array_sum($evaluation->getUserScoreList());
564
                            $result = [$sumResult, $studentCount];
565
                        }
566
567
                        return $result;
568
                        break;
569
                }
570
            }
571
        }
572
573
        $useSession = true;
574
        if (isset($stud_id) && empty($type)) {
575
            $key = 'result_score_student_list_'.api_get_course_int_id().'_'.api_get_session_id().'_'.$this->id.'_'.$stud_id;
576
            $data = Session::read('calc_score');
577
            $results = isset($data[$key]) ? $data[$key] : null;
578
579
            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...
580
                $results = null;
581
            }
582
            $results = null;
583
            if (empty($results)) {
584
                $results = Result::load(null, $stud_id, $this->id);
585
                Session::write('calc_score', [$key => $results]);
586
            }
587
588
            $score = 0;
589
            /** @var Result $res */
590
            foreach ($results as $res) {
591
                $score = $res->get_score();
592
            }
593
594
            return [$score, $this->get_max()];
595
        } else {
596
            $count = 0;
597
            $sum = 0;
598
            $bestResult = 0;
599
            $weight = 0;
600
            $sumResult = 0;
601
602
            $key = 'result_score_student_list_'.api_get_course_int_id().'_'.api_get_session_id().'_'.$this->id;
603
            $data = Session::read('calc_score');
604
            $allResults = isset($data[$key]) ? $data[$key] : null;
605
            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...
606
                $allResults = null;
607
            }
608
609
            if (empty($allResults)) {
610
                $allResults = Result::load(null, null, $this->id);
611
                Session::write($key, $allResults);
612
            }
613
614
            $students = [];
615
            /** @var Result $res */
616
            foreach ($allResults as $res) {
617
                $score = $res->get_score();
618
                if (!empty($score) || $score == '0') {
619
                    $count++;
620
                    $sum += $score / $this->get_max();
621
                    $sumResult += $score;
622
                    if ($score > $bestResult) {
623
                        $bestResult = $score;
624
                    }
625
                    $weight = $this->get_max();
626
                }
627
                $students[$res->get_user_id()] = $score;
628
            }
629
            if (empty($count)) {
630
                return null;
631
            }
632
633
            switch ($type) {
634
                case 'best':
635
                    return [$bestResult, $weight];
636
                    break;
637
                case 'average':
638
                    return [$sumResult / $count, $weight];
639
                    break;
640
                case 'ranking':
641
                    $students = [];
642
                    /** @var Result $res */
643
                    foreach ($allResults as $res) {
644
                        $score = $res->get_score();
645
                        $students[$res->get_user_id()] = $score;
646
                    }
647
648
                    return AbstractLink::getCurrentUserRanking($stud_id, $students);
649
                    break;
650
                default:
651
                    return [$sum, $count];
652
                    break;
653
            }
654
        }
655
    }
656
657
    /**
658
     * Generate an array of possible categories where this evaluation can be moved to.
659
     * Notice: its own parent will be included in the list: it's up to the frontend
660
     * to disable this element.
661
     *
662
     * @return array 2-dimensional array - every element contains 3 subelements (id, name, level)
663
     */
664
    public function get_target_categories()
665
    {
666
        // - course independent evaluation
667
        //   -> movable to root or other course independent categories
668
        // - evaluation inside a course
669
        //   -> movable to root, independent categories or categories inside the course
670
        $user = api_is_platform_admin() ? null : api_get_user_id();
671
        $targets = [];
672
        $level = 0;
673
        $root = [0, get_lang('RootCat'), $level];
674
        $targets[] = $root;
675
676
        if (isset($this->courseId) && !empty($this->courseId)) {
677
            $crscats = Category::load(null, null, $this->course_code, 0);
678
            foreach ($crscats as $cat) {
679
                $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
680
                $targets = $this->addTargetSubcategories($targets, $level + 1, $cat->get_id());
681
            }
682
        }
683
684
        $indcats = Category::load(null, $user, 0, 0);
685
        foreach ($indcats as $cat) {
686
            $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
687
            $targets = $this->addTargetSubcategories(
688
                $targets,
689
                $level + 1,
690
                $cat->get_id()
691
            );
692
        }
693
694
        return $targets;
695
    }
696
697
    /**
698
     * Move this evaluation to the given category.
699
     * If this evaluation moves from inside a course to outside,
700
     * its course code is also changed.
701
     */
702
    public function move_to_cat($cat)
703
    {
704
        $this->set_category_id($cat->get_id());
705
        if ($this->get_course_code() != $cat->get_course_code()) {
706
            $this->set_course_code($cat->get_course_code());
707
        }
708
        $this->save();
709
    }
710
711
    /**
712
     * Retrieve evaluations where a student has results for
713
     * and return them as an array of Evaluation objects.
714
     *
715
     * @param int $cat_id  parent category (use 'null' to retrieve them in all categories)
716
     * @param int $stud_id student id
717
     *
718
     * @return array
719
     */
720
    public static function get_evaluations_with_result_for_student($cat_id = null, $stud_id)
721
    {
722
        $tbl_grade_evaluations = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
723
        $tbl_grade_results = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
724
725
        $sql = 'SELECT * FROM '.$tbl_grade_evaluations.'
726
                WHERE id IN (
727
                    SELECT evaluation_id FROM '.$tbl_grade_results.'
728
                    WHERE user_id = '.intval($stud_id).' AND score IS NOT NULL
729
                )';
730
        if (!api_is_allowed_to_edit()) {
731
            $sql .= ' AND visible = 1';
732
        }
733
        if (isset($cat_id)) {
734
            $sql .= ' AND category_id = '.intval($cat_id);
735
        } else {
736
            $sql .= ' AND category_id >= 0';
737
        }
738
739
        $result = Database::query($sql);
740
        $alleval = self::create_evaluation_objects_from_sql_result($result);
741
742
        return $alleval;
743
    }
744
745
    /**
746
     * Get a list of students that do not have a result record for this evaluation.
747
     *
748
     * @param string $first_letter_user
749
     *
750
     * @return array
751
     */
752
    public function get_not_subscribed_students($first_letter_user = '')
753
    {
754
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
755
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
756
757
        $sql = "SELECT user_id,lastname,firstname,username 
758
                FROM $tbl_user 
759
                WHERE 
760
                    lastname LIKE '".Database::escape_string($first_letter_user)."%' AND 
761
                    status = ".STUDENT." AND user_id NOT IN (
762
                        SELECT user_id FROM $table 
763
                        WHERE evaluation_id = ".intval($this->id)."
764
                    )
765
                ORDER BY lastname";
766
767
        $result = Database::query($sql);
768
        $users = Database::store_result($result);
769
770
        return $users;
771
    }
772
773
    /**
774
     * Find evaluations by name.
775
     *
776
     * @param string $name_mask search string
777
     *
778
     * @return array evaluation objects matching the search criterium
779
     *
780
     * @todo can be written more efficiently using a new (but very complex) sql query
781
     */
782
    public function findEvaluations($name_mask, $selectcat)
783
    {
784
        $rootcat = Category::load($selectcat);
785
        $evals = $rootcat[0]->get_evaluations(
786
            (api_is_allowed_to_create_course() ? null : api_get_user_id()),
787
            true
788
        );
789
        $foundevals = [];
790
        foreach ($evals as $eval) {
791
            if (!(api_strpos(api_strtolower($eval->get_name()), api_strtolower($name_mask)) === false)) {
792
                $foundevals[] = $eval;
793
            }
794
        }
795
796
        return $foundevals;
797
    }
798
799
    public function get_item_type()
800
    {
801
        return 'E';
802
    }
803
804
    public function get_icon_name()
805
    {
806
        return $this->has_results() ? 'evalnotempty' : 'evalempty';
807
    }
808
809
    /**
810
     * Locks an evaluation, only one who can unlock it is the platform administrator.
811
     *
812
     * @param int locked 1 or unlocked 0
813
     */
814
    public function lock($locked)
815
    {
816
        $table_evaluation = Database::get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION);
817
        $sql = "UPDATE $table_evaluation 
818
                SET locked = '".intval($locked)."' 
819
                WHERE id='".intval($this->id)."'";
820
        Database::query($sql);
821
    }
822
823
    public function check_lock_permissions()
824
    {
825
        if (api_is_platform_admin()) {
826
            return true;
827
        } else {
828
            if ($this->is_locked()) {
829
                api_not_allowed();
830
            }
831
        }
832
    }
833
834
    public function delete_linked_data()
835
    {
836
    }
837
838
    /**
839
     * @return mixed
840
     */
841
    public function getStudentList()
842
    {
843
        return $this->studentList;
844
    }
845
846
    /**
847
     * @param $list
848
     */
849
    public function setStudentList($list)
850
    {
851
        $this->studentList = $list;
852
    }
853
854
    /**
855
     * @param int $evaluationId
856
     */
857
    public static function generateStats($evaluationId)
858
    {
859
        $allowStats = api_get_configuration_value('allow_gradebook_stats');
860
        if ($allowStats) {
861
            $evaluation = self::load($evaluationId);
862
863
            $results = Result::load(null, null, $evaluationId);
864
            $sumResult = 0;
865
            $bestResult = 0;
866
            $average = 0;
867
            $scoreList = [];
868
869
            if (!empty($results)) {
870
                /** @var Result $result */
871
                foreach ($results as $result) {
872
                    $score = $result->get_score();
873
                    $scoreList[$result->get_user_id()] = $score;
874
                    $sumResult += $score;
875
                    if ($score > $bestResult) {
876
                        $bestResult = $score;
877
                    }
878
                }
879
                $average = $sumResult / count($results);
880
            }
881
882
            /** @var Evaluation $evaluation */
883
            $evaluation = $evaluation[0];
884
            $evaluation = $evaluation->entity;
885
            $evaluation
886
                ->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

886
                ->/** @scrutinizer ignore-call */ 
887
                  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...
887
                ->setAverageScore($average)
888
                ->setUserScoreList($scoreList)
889
            ;
890
891
            $em = Database::getManager();
892
            $em->persist($evaluation);
893
            $em->flush();
894
        }
895
    }
896
897
    /**
898
     * @param int $courseId
899
     *
900
     * @return Evaluation
901
     */
902
    public function setCourseId($courseId)
903
    {
904
        $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...
905
906
        return $this;
907
    }
908
909
    /**
910
     * @param array $result
911
     *
912
     * @return array
913
     */
914
    private static function create_evaluation_objects_from_sql_result($result)
915
    {
916
        $alleval = [];
917
        $allow = api_get_configuration_value('allow_gradebook_stats');
918
        if ($allow) {
919
            $em = Database::getManager();
920
            $repo = $em->getRepository('ChamiloCoreBundle:GradebookEvaluation');
921
        }
922
923
        if (Database::num_rows($result)) {
924
            while ($data = Database::fetch_array($result)) {
925
                $eval = new Evaluation();
926
                $eval->set_id($data['id']);
927
                $eval->set_name($data['name']);
928
                $eval->set_description($data['description']);
929
                $eval->set_user_id($data['user_id']);
930
                $eval->setCourseId($data['c_id']);
931
                $courseInfo = api_get_course_info_by_id($data['c_id']);
932
                $eval->set_course_code($courseInfo['code']);
933
                $eval->set_category_id($data['category_id']);
934
                $eval->set_date(api_get_local_time($data['created_at']));
935
                $eval->set_weight($data['weight']);
936
                $eval->set_max($data['max']);
937
                $eval->set_visible($data['visible']);
938
                $eval->set_type($data['type']);
939
                $eval->set_locked($data['locked']);
940
                $eval->setSessionId(api_get_session_id());
941
942
                if ($allow) {
943
                    $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...
944
                }
945
946
                $alleval[] = $eval;
947
            }
948
        }
949
950
        return $alleval;
951
    }
952
953
    /**
954
     * Internal function used by get_target_categories().
955
     *
956
     * @param int $level
957
     *
958
     * @return array
959
     */
960
    private function addTargetSubcategories($targets, $level, $catid)
961
    {
962
        $subcats = Category::load(null, null, null, $catid);
963
        foreach ($subcats as $cat) {
964
            $targets[] = [$cat->get_id(), $cat->get_name(), $level + 1];
965
            $targets = $this->addTargetSubcategories(
966
                $targets,
967
                $level + 1,
968
                $cat->get_id()
969
            );
970
        }
971
972
        return $targets;
973
    }
974
}
975