Completed
Push — master ( 1ab056...1759c8 )
by Julito
55:42 queued 24:21
created

Category::get_parent_id()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\GradebookCategory;
5
6
/**
7
 * Class Category
8
 * Defines a gradebook Category object
9
 * @package chamilo.gradebook
10
 */
11
class Category implements GradebookItem
12
{
13
    private $id;
14
    private $name;
15
    private $description;
16
    private $user_id;
17
    private $course_code;
18
    private $courseId;
19
    private $parent;
20
    private $weight;
21
    private $visible;
22
    private $certificate_min_score;
23
    private $session_id;
24
    private $skills = array();
25
    private $grade_model_id;
26
    private $generateCertificates;
27
    private $isRequirement;
28
    public $studentList;
29
30
    /**
31
     * Consctructor
32
     */
33
    public function __construct()
34
    {
35
        $this->id = 0;
36
        $this->name = null;
37
        $this->description = null;
38
        $this->user_id = 0;
39
        $this->course_code = '';
40
        $this->courseId = 0;
41
        $this->parent = 0;
42
        $this->weight = 0;
43
        $this->visible = false;
44
        $this->certificate_min_score = 0;
45
        $this->session_id = 0;
46
        $this->grade_model_id = 0;
47
        $this->generateCertificates = false;
48
        $this->isRequirement = false;
49
    }
50
51
    /**
52
     * @return int
53
     */
54
    public function get_id()
55
    {
56
        return $this->id;
57
    }
58
59
    /**
60
     * @return string
61
     */
62
    public function get_name()
63
    {
64
        return $this->name;
65
    }
66
67
    /**
68
     * @return string
69
     */
70
    public function get_description()
71
    {
72
        return $this->description;
73
    }
74
75
    /**
76
     * @return int
77
     */
78
    public function get_user_id()
79
    {
80
        return $this->user_id;
81
    }
82
83
    /**
84
     * @return integer|null
85
     */
86
    public function get_certificate_min_score()
87
    {
88
        if (!empty($this->certificate_min_score)) {
89
            return $this->certificate_min_score;
90
        } else {
91
            return null;
92
        }
93
    }
94
95
    /**
96
     * @return string
97
     */
98
    public function get_course_code()
99
    {
100
        return $this->course_code;
101
    }
102
103
    /**
104
     * @return integer
105
     */
106
    public function get_parent_id()
107
    {
108
        return $this->parent;
109
    }
110
111
    /**
112
     * @return integer
113
     */
114
    public function get_weight()
115
    {
116
        return $this->weight;
117
    }
118
119
    /**
120
     * @return bool
121
     */
122
    public function is_locked()
123
    {
124
        return isset($this->locked) && $this->locked == 1 ? true : false;
125
    }
126
127
    /**
128
     * @return boolean
129
     */
130
    public function is_visible()
131
    {
132
        return $this->visible;
133
    }
134
135
    /**
136
     * Get $isRequirement
137
     * @return int
138
     */
139
    public function getIsRequirement()
140
    {
141
        return $this->isRequirement;
142
    }
143
144
    /**
145
     * @param int $id
146
     */
147
    public function set_id($id)
148
    {
149
        $this->id = $id;
150
    }
151
152
    /**
153
     * @param string $name
154
     */
155
    public function set_name($name)
156
    {
157
        $this->name = $name;
158
    }
159
160
    /**
161
     * @param string $description
162
     */
163
    public function set_description($description)
164
    {
165
        $this->description = $description;
166
    }
167
168
    /**
169
     * @param int $user_id
170
     */
171
    public function set_user_id($user_id)
172
    {
173
        $this->user_id = $user_id;
174
    }
175
176
    /**
177
     * @param string $course_code
178
     */
179
    public function set_course_code($course_code)
180
    {
181
        $this->course_code = $course_code;
182
    }
183
184
    /**
185
     * @param float $min_score
186
     */
187
    public function set_certificate_min_score($min_score = null)
188
    {
189
        $this->certificate_min_score = $min_score;
190
    }
191
192
    /**
193
     * @param int $parent
194
     */
195
    public function set_parent_id($parent)
196
    {
197
        $this->parent = intval($parent);
198
    }
199
200
    /**
201
     * Filters to int and sets the session ID
202
     * @param   int     The session ID from the Dokeos course session
203
     */
204
    public function set_session_id($session_id = 0)
205
    {
206
        $this->session_id = (int)$session_id;
207
    }
208
209
    /**
210
     * @param $weight
211
     */
212
    public function set_weight($weight)
213
    {
214
        $this->weight = $weight;
215
    }
216
217
    /**
218
     * @param $visible
219
     */
220
    public function set_visible($visible)
221
    {
222
        $this->visible = $visible;
223
    }
224
225
    /**
226
     * @param int $id
227
     */
228
    public function set_grade_model_id($id)
229
    {
230
        $this->grade_model_id = $id;
231
    }
232
233
    /**
234
     * @param $locked
235
     */
236
    public function set_locked($locked)
237
    {
238
        $this->locked = $locked;
239
    }
240
241
    /**
242
     * Set $isRequirement
243
     * @param int $isRequirement
244
     */
245
    public function setIsRequirement($isRequirement)
246
    {
247
        $this->isRequirement = $isRequirement;
248
    }
249
250
    /**
251
     * @return null|integer
252
     */
253
    public function get_grade_model_id()
254
    {
255
        if ($this->grade_model_id < 0) {
256
            return null;
257
        }
258
        return $this->grade_model_id;
259
    }
260
261
    /**
262
     * @return string
263
     */
264
    public function get_type()
265
    {
266
        return 'category';
267
    }
268
269
    /**
270
     * @param bool $from_db
271
     * @return array|resource
272
     */
273
    public function get_skills($from_db = true)
274
    {
275
        if ($from_db) {
276
            $cat_id = $this->get_id();
277
278
            $gradebook = new Gradebook();
279
            $skills = $gradebook->get_skills_by_gradebook($cat_id);
280
        } else {
281
            $skills = $this->skills;
282
        }
283
284
        return $skills;
285
    }
286
287
    /**
288
     * @return array
289
     */
290
    public function get_skills_for_select()
291
    {
292
        $skills = $this->get_skills();
293
        $skill_select = array();
294
        if (!empty($skills)) {
295
            foreach($skills as $skill) {
0 ignored issues
show
Bug introduced by
The expression $skills of type array|resource is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
296
                $skill_select[$skill['id']] = $skill['name'];
297
            }
298
        }
299
300
        return $skill_select;
301
    }
302
303
    /**
304
     * Set the generate_certificates value
305
     * @param int $generateCertificates
306
     */
307
    public function setGenerateCertificates($generateCertificates)
308
    {
309
        $this->generateCertificates = $generateCertificates;
310
    }
311
312
    /**
313
     * Get the generate_certificates value
314
     * @return int
315
     */
316
    public function getGenerateCertificates()
317
    {
318
        return $this->generateCertificates;
319
    }
320
321
    /**
322
     * @param int $id
323
     * @param int $session_id
324
     *
325
     * @return array
326
     */
327
    public static function load_session_categories($id = null, $session_id = null)
328
    {
329 View Code Duplication
        if (isset($id) && (int)$id === 0) {
330
            $cats = array();
331
            $cats[] = Category::create_root_category();
332
            return $cats;
333
        }
334
335
        $courseCode = api_get_course_info_by_id(api_get_course_int_id());
336
        $courseCode = $courseCode['code'];
337
        $session_id = intval($session_id);
338
339
        if (!empty($session_id)) {
340
            $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
341
            $sql = 'SELECT id, course_code
342
                    FROM '.$tbl_grade_categories. '
343
                    WHERE session_id = '.$session_id;
344
            $result_session = Database::query($sql);
345
            if (Database::num_rows($result_session) > 0) {
346
                $categoryList = array();
347
                while ($data_session = Database::fetch_array($result_session)) {
348
                    $parent_id = $data_session['id'];
349
                    if ($data_session['course_code'] == $courseCode) {
350
                        $categories = Category::load($parent_id);
351
                        $categoryList = array_merge($categoryList, $categories);
352
                    }
353
                }
354
355
                return $categoryList;
356
            }
357
        }
358
    }
359
360
    /**
361
     * Retrieve categories and return them as an array of Category objects
362
     * @param int      $id category id
363
     * @param int      $user_id (category owner)
364
     * @param string   $course_code
365
     * @param int      $parent_id parent category
366
     * @param bool     $visible
367
     * @param int      $session_id (in case we are in a session)
368
     * @param bool     $order_by Whether to show all "session"
369
     * categories (true) or hide them (false) in case there is no session id
370
     */
371
    public static function load(
372
        $id = null,
373
        $user_id = null,
374
        $course_code = null,
375
        $parent_id = null,
376
        $visible = null,
377
        $session_id = null,
378
        $order_by = null
379
    ) {
380
        //if the category given is explicitly 0 (not null), then create
381
        // a root category object (in memory)
382 View Code Duplication
        if (isset($id) && (int)$id === 0) {
383
            $cats = array();
384
            $cats[] = Category::create_root_category();
385
386
            return $cats;
387
        }
388
389
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
390
        $sql = 'SELECT * FROM '.$tbl_grade_categories;
391
        $paramcount = 0;
392
        if (isset($id)) {
393
            $sql.= ' WHERE id = '.intval($id);
394
            $paramcount ++;
395
        }
396
397 View Code Duplication
        if (isset($user_id)) {
398
            $user_id = intval($user_id);
399
            if ($paramcount != 0) {
400
                $sql .= ' AND';
401
            } else {
402
                $sql .= ' WHERE';
403
            }
404
            $sql .= ' user_id = '.intval($user_id);
405
            $paramcount++;
406
        }
407
408
        if (isset($course_code)) {
409
            if ($paramcount != 0) {
410
                $sql .= ' AND';
411
            } else {
412
                $sql .= ' WHERE';
413
            }
414
415
            if ($course_code == '0') {
416
                $sql .= ' c_id is null ';
417
            } else {
418
                $courseInfo = api_get_course_info($course_code);
419
                if ($courseInfo) {
420
                    $sql .= " c_id = '".intval($courseInfo['real_id'])."'";
421
                }
422
            }
423
424
            /*if ($show_session_categories !== true) {
425
                // a query on the course should show all
426
                // the categories inside sessions for this course
427
                // otherwise a special parameter is given to ask explicitely
428
                $sql .= " AND (session_id IS NULL OR session_id = 0) ";
429
            } else {*/
430
            if (empty($session_id)) {
431
                $sql .= ' AND (session_id IS NULL OR session_id = 0) ';
432
            } else {
433
                $sql .= ' AND session_id = '.(int)$session_id.' ';
434
            }
435
            //}
436
            $paramcount ++;
437
        }
438
439 View Code Duplication
        if (isset($parent_id)) {
440
            if ($paramcount != 0) {
441
                $sql .= ' AND ';
442
            } else {
443
                $sql .= ' WHERE ';
444
            }
445
            $sql .= ' parent_id = '.intval($parent_id);
446
            $paramcount++;
447
        }
448
449 View Code Duplication
        if (isset($visible)) {
450
            if ($paramcount != 0) {
451
                $sql .= ' AND';
452
            } else {
453
                $sql .= ' WHERE';
454
            }
455
            $sql .= ' visible = '.intval($visible);
456
        }
457
458
        if (!empty($order_by)) {
459
            if (!empty($order_by) && $order_by != '') {
460
                $sql .= ' '.$order_by;
461
            }
462
        }
463
464
        $result = Database::query($sql);
465
466
        $categories = array();
467
        if (Database::num_rows($result) > 0) {
468
            $categories = Category::create_category_objects_from_sql_result(
469
                $result
470
            );
471
        }
472
473
        return $categories;
474
    }
475
476
    /**
477
     * @return Category
478
     */
479
    private static function create_root_category()
480
    {
481
        $cat = new Category();
482
        $cat->set_id(0);
483
        $cat->set_name(get_lang('RootCat'));
484
        $cat->set_description(null);
485
        $cat->set_user_id(0);
486
        $cat->set_course_code(null);
487
        $cat->set_parent_id(null);
488
        $cat->set_weight(0);
489
        $cat->set_visible(1);
490
        $cat->setGenerateCertificates(0);
491
        $cat->setIsRequirement(false);
492
493
        return $cat;
494
    }
495
496
    /**
497
     * @param Doctrine\DBAL\Driver\Statement|null $result
498
     *
499
     * @return array
500
     */
501
    private static function create_category_objects_from_sql_result($result)
502
    {
503
        $categories = array();
504
        while ($data = Database::fetch_array($result)) {
0 ignored issues
show
Bug introduced by
It seems like $result defined by parameter $result on line 501 can be null; however, Database::fetch_array() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
505
            $cat = new Category();
506
            $cat->set_id($data['id']);
507
            $cat->set_name($data['name']);
508
            $cat->set_description($data['description']);
509
            $cat->set_user_id($data['user_id']);
510
            //$cat->set_course_code($data['course_code']);
511
            $cat->setCourseId($data['c_id']);
512
            $cat->set_parent_id($data['parent_id']);
513
            $cat->set_weight($data['weight']);
514
            $cat->set_visible($data['visible']);
515
            $cat->set_session_id($data['session_id']);
516
            $cat->set_certificate_min_score($data['certif_min_score']);
517
            $cat->set_grade_model_id($data['grade_model_id']);
518
            $cat->set_locked($data['locked']);
519
            $cat->setGenerateCertificates($data['generate_certificates']);
520
            $cat->setIsRequirement($data['is_requirement']);
521
            $categories[] = $cat;
522
        }
523
524
        return $categories;
525
    }
526
527
    /**
528
     * Create a category object from a GradebookCategory entity
529
     * @param GradebookCategory $gradebookCategory  The entity
530
     * @return \Category
531
     */
532
    public static function createCategoryObjectFromEntity(GradebookCategory $gradebookCategory)
533
    {
534
        $category = new Category();
535
        $category->set_id($gradebookCategory->getId());
536
        $category->set_name($gradebookCategory->getName());
537
        $category->set_description($gradebookCategory->getDescription());
538
        $category->set_user_id($gradebookCategory->getUserId());
539
        $category->set_course_code($gradebookCategory->getCourseCode());
0 ignored issues
show
Bug introduced by
The method getCourseCode() does not exist on Chamilo\CoreBundle\Entity\GradebookCategory. Did you maybe mean getCourse()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
540
        $category->set_parent_id($gradebookCategory->getParentId());
541
        $category->set_weight($gradebookCategory->getWeight());
542
        $category->set_visible($gradebookCategory->getVisible());
543
        $category->set_session_id($gradebookCategory->getSessionId());
544
        $category->set_certificate_min_score(
545
            $gradebookCategory->getCertifMinScore()
546
        );
547
        $category->set_grade_model_id($gradebookCategory->getGradeModelId());
548
        $category->set_locked($gradebookCategory->getLocked());
549
        $category->setGenerateCertificates(
550
            $gradebookCategory->getGenerateCertificates()
551
        );
552
        $category->setIsRequirement($gradebookCategory->getIsRequirement());
553
554
        return $category;
555
    }
556
557
    /**
558
     * Insert this category into the database
559
     */
560
    public function add()
561
    {
562
        if (isset($this->name) && '-1' == $this->name) {
563
            return false;
564
        }
565
566
        if (isset($this->name) && isset($this->user_id)) {
567
            $em = Database::getManager();
568
569
            $courseInfo = api_get_course_info($this->course_code);
570
            $course = api_get_user_course_entity($courseInfo['real_id']);
571
572
            $category = new GradebookCategory();
573
            $category->setName($this->name);
574
            $category->setDescription($this->description);
575
            $category->setUserId($this->user_id);
576
            $category->setCourse($course);
577
            $category->setParentId($this->parent);
578
            $category->setWeight($this->weight);
579
            $category->setVisible($this->visible);
580
            $category->setCertifMinScore($this->certificate_min_score);
581
            $category->setSessionId($this->session_id);
582
            $category->setGenerateCertificates($this->generateCertificates);
0 ignored issues
show
Bug introduced by
It seems like $this->generateCertificates can also be of type integer; however, Chamilo\CoreBundle\Entit...tGenerateCertificates() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
583
            $category->setGradeModelId($this->grade_model_id);
584
            $category->setIsRequirement($this->isRequirement);
0 ignored issues
show
Bug introduced by
It seems like $this->isRequirement can also be of type integer; however, Chamilo\CoreBundle\Entit...ory::setIsRequirement() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
585
            $category->setLocked(false);
586
587
            $em->persist($category);
588
            $em->flush();
589
590
            $id = $category->getId();
591
            $this->set_id($id);
592
593 View Code Duplication
            if (!empty($id)) {
594
595
                $parent_id = $this->get_parent_id();
596
                $grade_model_id = $this->get_grade_model_id();
597
                if ($parent_id == 0) {
598
                    //do something
599
                    if (isset($grade_model_id) && !empty($grade_model_id) && $grade_model_id != '-1') {
600
                        $obj = new GradeModel();
601
                        $components = $obj->get_components($grade_model_id);
602
                        $default_weight_setting = api_get_setting('gradebook_default_weight');
603
                        $default_weight = 100;
604
                        if (isset($default_weight_setting)) {
605
                            $default_weight = $default_weight_setting;
606
                        }
607
                        foreach ($components as $component) {
0 ignored issues
show
Bug introduced by
The expression $components of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
608
                            $gradebook =  new Gradebook();
609
                            $params = array();
610
611
                            $params['name'] = $component['acronym'];
612
                            $params['description'] = $component['title'];
613
                            $params['user_id'] = api_get_user_id();
614
                            $params['parent_id'] = $id;
615
                            $params['weight'] = $component['percentage'] / 100 * $default_weight;
616
                            $params['session_id'] = api_get_session_id();
617
                            $params['course_code'] = $this->get_course_code();
618
619
                            $gradebook->save($params);
620
                        }
621
                    }
622
                }
623
            }
624
625
            $gradebook= new Gradebook();
626
            $gradebook->update_skills_to_gradebook($this->id, $this->get_skills(false));
0 ignored issues
show
Bug introduced by
It seems like $this->get_skills(false) targeting Category::get_skills() can also be of type resource; however, Gradebook::update_skills_to_gradebook() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
627
628
            return $id;
629
        }
630
    }
631
632
    /**
633
     * Update the properties of this category in the database
634
     * @todo fix me
635
     */
636
    public function save()
637
    {
638
        $em = Database::getManager();
639
640
        $gradebookCategory = $em
641
            ->getRepository('ChamiloCoreBundle:GradebookCategory')
642
            ->find($this->id);
643
644
        if (empty($gradebookCategory)) {
645
            return false;
646
        }
647
648
        $gradebookCategory->setName($this->name);
649
        $gradebookCategory->setDescription($this->description);
650
        $gradebookCategory->setUserId($this->user_id);
651
        $gradebookCategory->setCourseCode($this->course_code);
652
        $gradebookCategory->setParentId($this->parent);
653
        $gradebookCategory->setWeight($this->weight);
654
        $gradebookCategory->setVisible($this->visible);
655
        $gradebookCategory->setCertifMinScore($this->certificate_min_score);
656
        $gradebookCategory->setGenerateCertificates(
657
            $this->generateCertificates
658
        );
659
        $gradebookCategory->setGradeModelId($this->grade_model_id);
660
        $gradebookCategory->setIsRequirement($this->isRequirement);
661
662
        $em->merge($gradebookCategory);
663
        $em->flush();
664
665
        if (!empty($this->id)) {
666
            $parent_id = $this->get_parent_id();
667
            $grade_model_id = $this->get_grade_model_id();
668 View Code Duplication
            if ($parent_id == 0) {
669
670
                if (isset($grade_model_id) && !empty($grade_model_id) && $grade_model_id != '-1') {
671
                    $obj = new GradeModel();
672
                    $components = $obj->get_components($grade_model_id);
673
                    $default_weight_setting = api_get_setting('gradebook_default_weight');
674
                    $default_weight = 100;
675
                    if (isset($default_weight_setting)) {
676
                        $default_weight = $default_weight_setting;
677
                    }
678
                    $final_weight = $this->get_weight();
679
                    if (!empty($final_weight)) {
680
                        $default_weight = $this->get_weight();
681
                    }
682
                    foreach ($components as $component) {
0 ignored issues
show
Bug introduced by
The expression $components of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
683
                        $gradebook = new Gradebook();
684
                        $params = array();
685
686
                        $params['name']             = $component['acronym'];
687
                        $params['description']      = $component['title'];
688
                        $params['user_id']          = api_get_user_id();
689
                        $params['parent_id']        = $this->id;
690
                        $params['weight']           = $component['percentage']/100*$default_weight;
691
                        $params['session_id']       = api_get_session_id();
692
                        $params['course_code']      = $this->get_course_code();
693
694
                        $gradebook->save($params);
695
                    }
696
                }
697
            }
698
        }
699
700
        $gradebook= new Gradebook();
701
        $gradebook->update_skills_to_gradebook(
702
            $this->id,
703
            $this->get_skills(false),
0 ignored issues
show
Bug introduced by
It seems like $this->get_skills(false) targeting Category::get_skills() can also be of type resource; however, Gradebook::update_skills_to_gradebook() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
704
            true
705
        );
706
    }
707
708
    /**
709
     * Update link weights see #5168
710
     * @param type $new_weight
711
     */
712
    public function update_children_weight($new_weight)
713
    {
714
        $links = $this->get_links();
715
        $old_weight = $this->get_weight();
716
717
        if (!empty($links)) {
718
            foreach ($links as $link_item) {
719
                if (isset($link_item)) {
720
                    $new_item_weight =  $new_weight * $link_item->get_weight() / $old_weight;
721
                    $link_item->set_weight($new_item_weight);
722
                    $link_item->save();
723
                }
724
            }
725
        }
726
    }
727
728
    /**
729
     * Delete this evaluation from the database
730
     */
731
    public function delete()
732
    {
733
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
734
        $sql = 'DELETE FROM '.$tbl_grade_categories.' WHERE id = '.intval($this->id);
735
        Database::query($sql);
736
    }
737
738
    /**
739
     * Not delete this category from the database,when visible=3 is category eliminated
740
     * @param int $courseId
741
     */
742 View Code Duplication
    public function update_category_delete($courseId)
743
    {
744
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
745
        $sql = 'UPDATE '.$tbl_grade_categories.' SET visible=3
746
                WHERE c_id ="'.intval($courseId).'"';
747
        Database::query($sql);
748
    }
749
750
     /**
751
     * Delete this category from the database
752
     * @param int $courseId
753
     */
754 View Code Duplication
    public static function deleteCategoryFromCourse($courseId)
755
    {
756
        $table = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
757
        $sql = 'DELETE FROM '.$table.' 
758
                WHERE c_id ="'.intval($courseId).'"';
759
        Database::query($sql);
760
    }
761
762
    /**
763
     * @param int $course_id
764
     * @return bool|string
765
     */
766
    public function show_message_resource_delete($course_id)
767
    {
768
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
769
        $sql = 'SELECT count(*) AS num from '.$tbl_grade_categories.'
770
                WHERE
771
                    c_id = "'.Database::escape_string($course_id).'" AND
772
                    visible=3';
773
        $res = Database::query($sql);
774
        $option = Database::fetch_array($res, 'ASSOC');
775
        if ($option['num']>=1) {
776
            return '&nbsp;&nbsp;<span class="resource-deleted">(&nbsp;'.get_lang('ResourceDeleted').'&nbsp;)</span>';
777
        } else {
778
            return false;
779
        }
780
    }
781
782
    /**
783
     * Shows all information of an category
784
     */
785 View Code Duplication
    public function shows_all_information_an_category($selectcat = '')
786
    {
787
        if ($selectcat == '') {
788
            return null;
789
        } else {
790
            $tbl_category = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
791
            $sql = 'SELECT 
792
                        name,
793
                        description,
794
                        user_id,
795
                        c_id,
796
                        parent_id,
797
                        weight,
798
                        visible,
799
                        certif_min_score,
800
                        session_id, 
801
                        generate_certificates, 
802
                        is_requirement
803
                    FROM '.$tbl_category.' c
804
                    WHERE c.id='.intval($selectcat);
805
            $result = Database::query($sql);
806
            $row = Database::fetch_array($result, 'ASSOC');
807
808
            return $row;
809
        }
810
    }
811
812
    /**
813
     * Check if a category name (with the same parent category) already exists
814
     * @param $name name to check (if not given, the name property of this object will be checked)
815
     * @param $parent parent category
816
     */
817
    public function does_name_exist($name, $parent)
818
    {
819
        if (!isset ($name)) {
820
            $name = $this->name;
821
            $parent = $this->parent;
822
        }
823
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
824
        $sql = 'SELECT count(id) AS number'
825
            .' FROM '.$tbl_grade_categories
826
            ." WHERE name = '".Database::escape_string($name)."'";
827
828
        if (api_is_allowed_to_edit()) {
829
            $parent = Category::load($parent);
830
            $code = $parent[0]->get_course_code();
831
            $courseInfo = api_get_course_info($code);
832
            $courseId = $courseInfo['real_id'];
833
            if (isset($code) && $code != '0') {
834
                $main_course_user_table = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
835
                $sql .= ' AND user_id IN (
836
                            SELECT user_id FROM '.$main_course_user_table.'
837
                            WHERE c_id = '.$courseId.' AND status = '.COURSEMANAGER.'
838
                        )';
839
            } else {
840
                $sql .= ' AND user_id = '.api_get_user_id();
841
            }
842
843
        } else {
844
            $sql .= ' AND user_id = '.api_get_user_id();
845
        }
846
        if (!isset ($parent)) {
847
            $sql.= ' AND parent_id is null';
848
        } else {
849
            $sql.= ' AND parent_id = '.intval($parent);
850
        }
851
852
        $result = Database::query($sql);
853
        $number = Database::fetch_row($result);
854
        return ($number[0] != 0);
855
    }
856
857
    /**
858
     * Checks if the certificate is available for the given user in this category
859
     * @param   integer    $user_id User ID
860
     * @return  boolean    True if conditions match, false if fails
861
     */
862
    public function is_certificate_available($user_id)
863
    {
864
        $score = $this->calc_score(
865
            $user_id,
866
            null,
867
            $this->course_code,
868
            $this->session_id
869
        );
870
871
        if (isset($score) && isset($score[0])) {
872
            // Get a percentage score to compare to minimum certificate score
873
            //$certification_score = $score[0] / $score[1] * 100;
874
875
            // Get real score not a percentage.
876
            $certification_score = $score[0];
877
878
            if ($certification_score >= $this->certificate_min_score) {
879
                return true;
880
            }
881
        }
882
883
        return false;
884
    }
885
886
    /**
887
     * Is this category a course ?
888
     * A category is a course if it has a course code and no parent category.
889
     */
890
    public function is_course()
891
    {
892
        return (isset($this->course_code) && !empty($this->course_code)
893
            && (!isset($this->parent) || $this->parent == 0));
894
    }
895
896
    /**
897
     * Calculate the score of this category
898
     * @param integer $stud_id student id (default: all students - then the average is returned)
899
     * @param integer $session_id
900
     * @return    array (score sum, weight sum)
901
     *             or null if no scores available
902
     */
903
    public function calc_score(
904
        $stud_id = null,
905
        $type = null,
906
        $course_code = '',
907
        $session_id = null
908
    ) {
909
        // Classic
910
        if (!empty($stud_id) && $type == '') {
911
            if (!empty($course_code)) {
912
                $cats = $this->get_subcategories(
913
                    $stud_id,
914
                    $course_code,
915
                    $session_id
916
                );
917
                $evals = $this->get_evaluations($stud_id, false, $course_code);
918
                $links = $this->get_links($stud_id, false, $course_code);
919
            } else {
920
                $cats = $this->get_subcategories($stud_id);
921
                $evals = $this->get_evaluations($stud_id);
922
                $links = $this->get_links($stud_id);
923
            }
924
925
            // Calculate score
926
            $count = 0;
927
            $ressum = 0;
928
            $weightsum = 0;
929
930 View Code Duplication
            if (!empty($cats)) {
931
                /** @var Category $cat */
932
                foreach ($cats as $cat) {
933
                    $cat->set_session_id($session_id);
934
                    $cat->set_course_code($course_code);
935
                    $cat->setStudentList($this->getStudentList());
936
                    $score = $cat->calc_score(
937
                        $stud_id,
938
                        null,
939
                        $course_code,
940
                        $session_id
941
                    );
942
943
                    $catweight = 0;
944
                    if ($cat->get_weight() != 0) {
945
                        $catweight = $cat->get_weight();
946
                        $weightsum += $catweight;
947
                    }
948
949
                    if (isset($score) && !empty($score[1]) && !empty($catweight)) {
950
                        $ressum += $score[0]/$score[1] * $catweight;
951
                    }
952
                }
953
            }
954
955
            $students = array();
956
957
            if (!empty($evals)) {
958
                /** @var Evaluation $eval */
959
                foreach ($evals as $eval) {
960
                    $eval->setStudentList($this->getStudentList());
961
                    $evalres = $eval->calc_score($stud_id, null);
962
963
                    if (isset($evalres) && $eval->get_weight() != 0) {
964
                        $evalweight = $eval->get_weight();
965
                        $weightsum += $evalweight;
966
                        $count++;
967 View Code Duplication
                        if (!empty($evalres[1])) {
968
                            $ressum += $evalres[0] / $evalres[1] * $evalweight;
969
                        }
970
                    } else {
971
                        if ($eval->get_weight() != 0) {
972
                            $evalweight = $eval->get_weight();
973
                            $weightsum += $evalweight;
974
                        }
975
                    }
976
                }
977
            }
978
979
            if (!empty($links)) {
980
                /** @var EvalLink|ExerciseLink $link */
981
                foreach ($links as $link) {
982
                    $link->setStudentList($this->getStudentList());
983
                    $linkres = $link->calc_score($stud_id, null);
984
                    if (!empty($linkres) && $link->get_weight() != 0) {
985
                        $students[$stud_id] = $linkres[0];
986
                        $linkweight = $link->get_weight();
987
                        $link_res_denom = $linkres[1] == 0 ? 1 : $linkres[1];
988
                        $count++;
989
                        $weightsum += $linkweight;
990
                        $ressum += $linkres[0] / $link_res_denom * $linkweight;
991
                    } else {
992
                        // Adding if result does not exists
993
                        if ($link->get_weight() != 0) {
994
                            $linkweight = $link->get_weight();
995
                            $weightsum += $linkweight;
996
                        }
997
                    }
998
                }
999
            }
1000
        } else {
1001
            if (!empty($course_code)) {
1002
                $cats = $this->get_subcategories(
1003
                    null,
1004
                    $course_code,
1005
                    $session_id
1006
                );
1007
                $evals = $this->get_evaluations(null, false, $course_code);
1008
                $links = $this->get_links(null, false, $course_code);
1009
            } else {
1010
                $cats = $this->get_subcategories(null);
1011
                $evals = $this->get_evaluations(null);
1012
                $links = $this->get_links(null);
1013
            }
1014
1015
            // Calculate score
1016
            $count = 0;
1017
            $ressum = 0;
1018
            $weightsum = 0;
1019
            $bestResult = 0;
1020
1021 View Code Duplication
            if (!empty($cats)) {
1022
                /** @var Category $cat */
1023
                foreach ($cats as $cat) {
1024
                    $cat->setStudentList($this->getStudentList());
1025
                    $score = $cat->calc_score(
1026
                        null,
1027
                        $type,
1028
                        $course_code,
1029
                        $session_id
1030
                    );
1031
1032
                    $catweight = 0;
1033
                    if ($cat->get_weight() != 0) {
1034
                        $catweight = $cat->get_weight();
1035
                        $weightsum += $catweight;
1036
                    }
1037
1038
                    if (isset($score) && !empty($score[1]) && !empty($catweight)) {
1039
                        $ressum += $score[0]/$score[1] * $catweight;
1040
1041
                        if ($ressum > $bestResult) {
1042
                            $bestResult = $ressum;
1043
                        }
1044
                    }
1045
1046
                }
1047
            }
1048
1049
            if (!empty($evals)) {
1050
                /** @var Evaluation $eval */
1051
                foreach ($evals as $eval) {
1052
                    $evalres = $eval->calc_score(null, $type);
1053
                    $eval->setStudentList($this->getStudentList());
1054
1055
                    if (isset($evalres) && $eval->get_weight() != 0) {
1056
                        $evalweight = $eval->get_weight();
1057
                        $weightsum += $evalweight;
1058
                        $count++;
1059 View Code Duplication
                        if (!empty($evalres[1])) {
1060
                            $ressum += $evalres[0] / $evalres[1] * $evalweight;
1061
                        }
1062
1063
                        if ($ressum > $bestResult) {
1064
                            $bestResult = $ressum;
1065
                        }
1066
1067
                    } else {
1068
                        if ($eval->get_weight() != 0) {
1069
                            $evalweight = $eval->get_weight();
1070
                            $weightsum += $evalweight;
1071
                        }
1072
                    }
1073
                }
1074
            }
1075
            if (!empty($links)) {
1076
                /** @var EvalLink|ExerciseLink $link */
1077
                foreach ($links as $link) {
1078
                    $link->setStudentList($this->getStudentList());
1079
                    $linkres = $link->calc_score($stud_id, $type);
1080
                    if (!empty($linkres) && $link->get_weight() != 0) {
1081
                        $students[$stud_id] = $linkres[0];
1082
                        $linkweight = $link->get_weight();
1083
                        $link_res_denom = $linkres[1] == 0 ? 1 : $linkres[1];
1084
1085
                        $count++;
1086
                        $weightsum += $linkweight;
1087
                        $ressum += $linkres[0] / $link_res_denom * $linkweight;
1088
1089
                        if ($ressum > $bestResult) {
1090
                            $bestResult = $ressum;
1091
                        }
1092
                    } else {
1093
                        // Adding if result does not exists
1094
                        if ($link->get_weight() != 0) {
1095
                            $linkweight = $link->get_weight();
1096
                            $weightsum += $linkweight;
1097
                        }
1098
                    }
1099
                }
1100
            }
1101
        }
1102
1103
        switch ($type) {
1104
            case 'best':
1105
                if (empty($bestResult)) {
1106
                    return null;
1107
                }
1108
                return array($bestResult, $weightsum);
1109
                break;
1110
            case 'average':
1111
                if (empty($ressum)) {
1112
                    return null;
1113
                }
1114
                return array($ressum, $weightsum);
1115
                break;
1116
            case 'ranking':
1117
                // category ranking is calculated in gradebook_data_generator.class.php
1118
                // function get_data
1119
                return null;
1120
                return AbstractLink::getCurrentUserRanking($stud_id, array());
0 ignored issues
show
Unused Code introduced by
return \AbstractLink::ge...ing($stud_id, array()); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1121
                break;
1122
            default:
1123
                return array($ressum, $weightsum);
1124
                break;
1125
        }
1126
    }
1127
1128
    /**
1129
     * Delete this category and every subcategory, evaluation and result inside
1130
     */
1131
    public function delete_all()
1132
    {
1133
        $cats  = Category::load(null, null, $this->course_code, $this->id, null);
1134
        $evals = Evaluation::load(null, null, $this->course_code, $this->id, null);
1135
        $links = LinkFactory::load(null, null, null, null, $this->course_code, $this->id, null);
1136
        if (!empty($cats)) {
1137
            foreach ($cats as $cat) {
1138
                $cat->delete_all();
1139
                $cat->delete();
1140
            }
1141
        }
1142
        if (!empty($evals)) {
1143
            foreach ($evals as $eval) {
1144
                $eval->delete_with_results();
1145
            }
1146
        }
1147
        if (!empty($links)) {
1148
            foreach ($links as $link) {
1149
                $link->delete();
1150
            }
1151
        }
1152
        $this->delete();
1153
    }
1154
1155
    /**
1156
     * Return array of Category objects where a student is subscribed to.
1157
     * @param int       student id
1158
     * @param string    Course code
1159
     * @param int       Session id
1160
     * @param integer $stud_id
1161
     * @param string $course_code
1162
     * @param integer $session_id
1163
     */
1164
    public function get_root_categories_for_student($stud_id, $course_code = null, $session_id = null)
1165
    {
1166
        $main_course_user_table = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1167
        $courseTable = Database :: get_main_table(TABLE_MAIN_COURSE);
1168
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1169
1170
        $sql = "SELECT * FROM $tbl_grade_categories WHERE parent_id = 0";
1171
1172
        if (!api_is_allowed_to_edit()) {
1173
            $sql .= ' AND visible = 1';
1174
            //proceed with checks on optional parameters course & session
1175 View Code Duplication
            if (!empty($course_code)) {
1176
                // TODO: considering it highly improbable that a user would get here
1177
                // if he doesn't have the rights to view this course and this
1178
                // session, we don't check his registration to these, but this
1179
                // could be an improvement
1180
                if (!empty($session_id)) {
1181
                    $sql .= " AND course_code = '".Database::escape_string($course_code)."' AND session_id = ".(int)$session_id;
1182
                } else {
1183
                    $sql .= " AND course_code = '".Database::escape_string($course_code)."' AND session_id is null OR session_id=0";
1184
                }
1185
            } else {
1186
                //no optional parameter, proceed as usual
1187
                $sql .= ' AND course_code in
1188
                     (
1189
                        SELECT c.code
1190
                        FROM '.$main_course_user_table.' cu INNER JOIN '.$courseTable.' c
1191
                        ON (cu.c_id = c.id)
1192
                        WHERE cu.user_id = '.intval($stud_id).'
1193
                        AND cu.status = '.STUDENT.'
1194
                    )';
1195
            }
1196
        } elseif (api_is_allowed_to_edit() && !api_is_platform_admin()) {
1197
            //proceed with checks on optional parameters course & session
1198 View Code Duplication
            if (!empty($course_code)) {
1199
                // TODO: considering it highly improbable that a user would get here
1200
                // if he doesn't have the rights to view this course and this
1201
                // session, we don't check his registration to these, but this
1202
                // could be an improvement
1203
                $sql .= " AND course_code  = '".Database::escape_string($course_code)."'";
1204
                if (!empty($session_id)) {
1205
                    $sql .= " AND session_id = ".(int)$session_id;
1206
                } else {
1207
                    $sql .="AND session_id IS NULL OR session_id=0";
1208
                }
1209
            } else {
1210
                $sql .= ' AND course_code IN
1211
                     (
1212
                        SELECT c.code
1213
                        FROM '.$main_course_user_table.' cu INNER JOIN '.$courseTable.' c
1214
                        ON (cu.c_id = c.id)
1215
                        WHERE
1216
                            cu.user_id = '.api_get_user_id().' AND
1217
                            cu.status = '.COURSEMANAGER.'
1218
                    )';
1219
            }
1220
        }elseif (api_is_platform_admin()) {
1221
            if (isset($session_id) && $session_id!=0) {
1222
                $sql.=' AND session_id='.intval($session_id);
1223
            } else {
1224
                $sql.=' AND coalesce(session_id,0)=0';
1225
            }
1226
        }
1227
        $result = Database::query($sql);
1228
        $cats = Category::create_category_objects_from_sql_result($result);
1229
1230
        // course independent categories
1231
        if (empty($course_code)) {
1232
            $cats = Category::get_independent_categories_with_result_for_student (0, $stud_id, $cats);
1233
        }
1234
1235
        return $cats;
1236
    }
1237
1238
    /**
1239
     * Return array of Category objects where a teacher is admin for.
1240
     * @param int user id (to return everything, use 'null' here)
1241
     * @param string course code (optional)
1242
     * @param int session id (optional)
1243
     * @param integer $user_id
1244
     * @param string $course_code
1245
     * @param integer $session_id
1246
     */
1247
    public function get_root_categories_for_teacher($user_id, $course_code = null, $session_id = null)
1248
    {
1249
        if ($user_id == null) {
1250
            return Category::load(null,null,$course_code,0,null,$session_id);
1251
        }
1252
1253
        $courseTable = Database :: get_main_table(TABLE_MAIN_COURSE);
1254
        $main_course_user_table = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1255
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1256
1257
        $sql = 'SELECT * FROM '.$tbl_grade_categories.'
1258
                WHERE parent_id = 0';
1259
        if (!empty($course_code)) {
1260
            $sql .= " AND course_code = '".Database::escape_string($course_code)."' ";
1261
            if (!empty($session_id)) {
1262
                $sql .= " AND session_id = ".(int)$session_id;
1263
            }
1264
        } else {
1265
            $sql .= ' AND course_code in
1266
                 (
1267
                    SELECT c.code
1268
                    FROM '.$main_course_user_table.' cu
1269
                    INNER JOIN '.$courseTable.' c
1270
                    ON (cu.c_id = c.id)
1271
                    WHERE user_id = '.intval($user_id).'
1272
                )';
1273
        }
1274
        $result = Database::query($sql);
1275
        $cats = Category::create_category_objects_from_sql_result($result);
1276
        // course independent categories
1277
        if (isset($course_code)) {
1278
            $indcats = Category::load(null,$user_id,$course_code,0,null,$session_id);
1279
            $cats = array_merge($cats, $indcats);
1280
        }
1281
1282
        return $cats;
1283
    }
1284
1285
    /**
1286
     * Can this category be moved to somewhere else ?
1287
     * The root and courses cannot be moved.
1288
     */
1289
    public function is_movable()
1290
    {
1291
        return (!(!isset ($this->id) || $this->id == 0 || $this->is_course()));
1292
    }
1293
1294
    /**
1295
     * Generate an array of possible categories where this category can be moved to.
1296
     * Notice: its own parent will be included in the list: it's up to the frontend
1297
     * to disable this element.
1298
     * @return array 2-dimensional array - every element contains 3 subelements (id, name, level)
1299
     */
1300
    public function get_target_categories()
1301
    {
1302
        // the root or a course -> not movable
1303
        if (!$this->is_movable()) {
1304
            return null;
1305
        } else {
1306
1307
            // otherwise:
1308
            // - course independent category
1309
            //   -> movable to root or other independent categories
1310
            // - category inside a course
1311
            //   -> movable to root, independent categories or categories inside the course
1312
1313
            $user = (api_is_platform_admin() ? null : api_get_user_id());
1314
            $targets = array();
1315
            $level = 0;
1316
1317
            $root = array(0, get_lang('RootCat'), $level);
1318
            $targets[] = $root;
1319
1320 View Code Duplication
            if (isset($this->course_code) && !empty($this->course_code)) {
1321
                $crscats = Category::load(null,null,$this->course_code,0);
1322
                foreach ($crscats as $cat) {
1323
                    if ($this->can_be_moved_to_cat($cat)) {
1324
                        $targets[] = array ($cat->get_id(), $cat->get_name(), $level+1);
1325
                        $targets = $this->add_target_subcategories($targets, $level+1, $cat->get_id());
1326
                    }
1327
                }
1328
            }
1329
1330
            $indcats = Category::load(null,$user,0,0);
1331
            foreach ($indcats as $cat) {
1332
                if ($this->can_be_moved_to_cat($cat)) {
1333
                    $targets[] = array ($cat->get_id(), $cat->get_name(), $level+1);
1334
                    $targets = $this->add_target_subcategories($targets, $level+1, $cat->get_id());
1335
                }
1336
            }
1337
1338
            return $targets;
1339
        }
1340
    }
1341
1342
    /**
1343
     * Internal function used by get_target_categories()
1344
     * @param integer $level
1345
     */
1346 View Code Duplication
    private function add_target_subcategories($targets, $level, $catid)
1347
    {
1348
        $subcats = Category::load(null,null,null,$catid);
1349
        foreach ($subcats as $cat) {
1350
            if ($this->can_be_moved_to_cat($cat)) {
1351
                $targets[] = array ($cat->get_id(), $cat->get_name(), $level+1);
1352
                $targets = $this->add_target_subcategories($targets, $level+1, $cat->get_id());
1353
            }
1354
        }
1355
1356
        return $targets;
1357
    }
1358
1359
    /**
1360
     * Internal function used by get_target_categories() and add_target_subcategories()
1361
     * Can this category be moved to the given category ?
1362
     * Impossible when origin and target are the same... children won't be processed
1363
     * either. (a category can't be moved to one of its own children)
1364
     */
1365
    private function can_be_moved_to_cat ($cat)
1366
    {
1367
        return $cat->get_id() != $this->get_id();
1368
    }
1369
1370
    /**
1371
     * Move this category to the given category.
1372
     * If this category moves from inside a course to outside,
1373
     * its course code must be changed, as well as the course code
1374
     * of all underlying categories and evaluations. All links will
1375
     * be deleted as well !
1376
     */
1377
    public function move_to_cat($cat)
1378
    {
1379
        $this->set_parent_id($cat->get_id());
1380
        if ($this->get_course_code() != $cat->get_course_code()) {
1381
            $this->set_course_code($cat->get_course_code());
1382
            $this->apply_course_code_to_children();
1383
        }
1384
        $this->save();
1385
    }
1386
1387
    /**
1388
     * Internal function used by move_to_cat()
1389
     */
1390
    private function apply_course_code_to_children()
1391
    {
1392
        $cats = Category::load(null, null, null, $this->id, null);
1393
        $evals = Evaluation::load(null, null, null, $this->id, null);
1394
        $links = LinkFactory::load(null,null,null,null,null,$this->id,null);
1395
1396
        foreach ($cats as $cat) {
1397
            $cat->set_course_code($this->get_course_code());
1398
            $cat->save();
1399
            $cat->apply_course_code_to_children();
1400
        }
1401
1402
        foreach ($evals as $eval) {
1403
            $eval->set_course_code($this->get_course_code());
1404
            $eval->save();
1405
        }
1406
1407
        foreach ($links as $link) {
1408
            $link->delete();
1409
        }
1410
    }
1411
1412
    /**
1413
     * Generate an array of all categories the user can navigate to
1414
     */
1415
    public function get_tree()
1416
    {
1417
        $targets = array();
1418
        $level = 0;
1419
        $root = array(0, get_lang('RootCat'), $level);
1420
        $targets[] = $root;
1421
1422
        // course or platform admin
1423
        if (api_is_allowed_to_edit()) {
1424
            $user = (api_is_platform_admin() ? null : api_get_user_id());
1425
            $cats = Category::get_root_categories_for_teacher($user);
1426
            foreach ($cats as $cat) {
1427
                $targets[] = array ($cat->get_id(), $cat->get_name(), $level+1);
1428
                $targets = Category::add_subtree($targets, $level+1, $cat->get_id(),null);
1429
            }
1430
        } else {
1431
            // student
1432
            $cats = Category::get_root_categories_for_student(api_get_user_id());
1433
            foreach ($cats as $cat) {
1434
                $targets[] = array ($cat->get_id(), $cat->get_name(), $level+1);
1435
                $targets = Category::add_subtree($targets, $level+1, $cat->get_id(), 1);
1436
            }
1437
        }
1438
1439
        return $targets;
1440
    }
1441
1442
    /**
1443
     * Internal function used by get_tree()
1444
     * @param integer $level
1445
     * @param null|integer $visible
1446
     */
1447
    private function add_subtree ($targets, $level, $catid, $visible)
1448
    {
1449
        $subcats = Category::load(null,null,null,$catid,$visible);
0 ignored issues
show
Bug introduced by
It seems like $visible defined by parameter $visible on line 1447 can also be of type integer; however, Category::load() does only seem to accept boolean|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1450
1451
        if (!empty($subcats)) {
1452
            foreach ($subcats as $cat) {
1453
                $targets[] = array ($cat->get_id(), $cat->get_name(), $level+1);
1454
                $targets = Category::add_subtree($targets, $level+1, $cat->get_id(),$visible);
1455
            }
1456
        }
1457
1458
        return $targets;
1459
    }
1460
1461
    /**
1462
     * Generate an array of courses that a teacher hasn't created a category for.
1463
     * @param integer $user_id
1464
     * @return array 2-dimensional array - every element contains 2 subelements (code, title)
1465
     */
1466
    public function get_not_created_course_categories ($user_id)
1467
    {
1468
        $tbl_main_courses = Database :: get_main_table(TABLE_MAIN_COURSE);
1469
        $tbl_main_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1470
        $tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1471
1472
        $sql = 'SELECT DISTINCT(code), title
1473
                FROM '.$tbl_main_courses.' cc, '.$tbl_main_course_user.' cu'
1474
            .' WHERE cc.id = cu.c_id '
1475
            .' AND cu.status = '.COURSEMANAGER;
1476
        if (!api_is_platform_admin()) {
1477
            $sql .= ' AND cu.user_id = '.$user_id;
1478
        }
1479
        $sql .= ' AND cc.code NOT IN
1480
             (
1481
                SELECT course_code FROM '.$tbl_grade_categories.'
1482
                WHERE
1483
                    parent_id = 0 AND
1484
                    course_code IS NOT NULL
1485
                )';
1486
        $result = Database::query($sql);
1487
1488
        $cats=array();
1489 View Code Duplication
        while ($data=Database::fetch_array($result)) {
1490
            $cats[] = array ($data['code'], $data['title']);
1491
        }
1492
1493
        return $cats;
1494
    }
1495
1496
    /**
1497
     * Generate an array of all courses that a teacher is admin of.
1498
     * @param integer $user_id
1499
     * @return array 2-dimensional array - every element contains 2 subelements (code, title)
1500
     */
1501
    public function get_all_courses ($user_id)
1502
    {
1503
        $tbl_main_courses = Database :: get_main_table(TABLE_MAIN_COURSE);
1504
        $tbl_main_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1505
        $sql = 'SELECT DISTINCT(code), title
1506
                FROM '.$tbl_main_courses.' cc, '.$tbl_main_course_user.' cu
1507
                WHERE cc.id = cu.c_id AND cu.status = '.COURSEMANAGER;
1508
        if (!api_is_platform_admin()) {
1509
            $sql .= ' AND cu.user_id = '.intval($user_id);
1510
        }
1511
1512
        $result = Database::query($sql);
1513
        $cats = array();
1514 View Code Duplication
        while ($data = Database::fetch_array($result)) {
1515
            $cats[] = array ($data['code'], $data['title']);
1516
        }
1517
1518
        return $cats;
1519
    }
1520
1521
    /**
1522
     * Apply the same visibility to every subcategory, evaluation and link
1523
     */
1524
    public function apply_visibility_to_children()
1525
    {
1526
        $cats = Category::load(null, null, null, $this->id, null);
1527
        $evals = Evaluation::load(null, null, null, $this->id, null);
1528
        $links = LinkFactory::load(null,null,null,null,null,$this->id,null);
1529
        if (!empty($cats)) {
1530
            foreach ($cats as $cat) {
1531
                $cat->set_visible($this->is_visible());
1532
                $cat->save();
1533
                $cat->apply_visibility_to_children();
1534
            }
1535
        }
1536
        if (!empty($evals)) {
1537
            foreach ($evals as $eval) {
1538
                $eval->set_visible($this->is_visible());
1539
                $eval->save();
1540
            }
1541
        }
1542
        if (!empty($links)) {
1543
            foreach ($links as $link) {
1544
                $link->set_visible($this->is_visible());
1545
                $link->save();
1546
            }
1547
        }
1548
    }
1549
1550
    /**
1551
     * Check if a category contains evaluations with a result for a given student
1552
     */
1553
    public function has_evaluations_with_results_for_student($stud_id)
1554
    {
1555
        $evals = Evaluation::get_evaluations_with_result_for_student($this->id, $stud_id);
1556
        if (count($evals) != 0) {
1557
            return true;
1558
        } else {
1559
            $cats = Category::load(
1560
                null,
1561
                null,
1562
                null,
1563
                $this->id,
1564
                api_is_allowed_to_edit() ? null : 1
1565
            );
1566
            foreach ($cats as $cat) {
1567
                if ($cat->has_evaluations_with_results_for_student($stud_id)) {
1568
                    return true;
1569
                }
1570
            }
1571
1572
            return false;
1573
        }
1574
    }
1575
1576
    /**
1577
     * Retrieve all categories inside a course independent category
1578
     * that should be visible to a student.
1579
     * @param integer $cat_id parent category
1580
     * @param $stud_id student id
1581
     * @param $cats optional: if defined, the categories will be added to this array
1582
     */
1583
    public function get_independent_categories_with_result_for_student($cat_id, $stud_id, $cats = array())
1584
    {
1585
        $creator = api_is_allowed_to_edit() && !api_is_platform_admin() ? api_get_user_id() : null;
1586
1587
        $crsindcats = Category::load(
1588
            null,
1589
            $creator,
1590
            '0',
1591
            $cat_id,
1592
            api_is_allowed_to_edit() ? null : 1
1593
        );
1594
1595
        if (!empty($crsindcats)) {
1596
            foreach ($crsindcats as $crsindcat) {
1597
                if ($crsindcat->has_evaluations_with_results_for_student($stud_id)) {
1598
                    $cats[] = $crsindcat;
1599
                }
1600
            }
1601
        }
1602
        return $cats;
1603
    }
1604
1605
    /**
1606
     * Return the session id (in any case, even if it's null or 0)
1607
     * @return  int Session id (can be null)
1608
     */
1609
    public function get_session_id()
1610
    {
1611
        return $this->session_id;
1612
    }
1613
1614
    /**
1615
     * Get appropriate subcategories visible for the user (and optionally the course and session)
1616
     * @param int    $stud_id student id (default: all students)
1617
     * @param string $course_code Course code (optional)
1618
     * @param int    $session_id Session ID (optional)
1619
     * @param bool   $order
1620
1621
     * @return array Array of subcategories
1622
     */
1623
    public function get_subcategories($stud_id = null, $course_code = null, $session_id = null, $order = null)
1624
    {
1625
        if (!empty($session_id)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1626
            /*$tbl_grade_categories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1627
            $sql = 'SELECT id FROM '.$tbl_grade_categories. ' WHERE session_id = '.$session_id;
1628
            $result_session = Database::query($sql);
1629
            if (Database::num_rows($result_session) > 0) {
1630
                $data_session = Database::fetch_array($result_session);
1631
                $parent_id = $data_session['id'];
1632
                return Category::load(null, null, null, $parent_id, null, null, $order);
1633
            }*/
1634
        }
1635
1636
        // 1 student
1637
        if (isset($stud_id)) {
1638
            // Special case: this is the root
1639
            if ($this->id == 0) {
1640
                return Category::get_root_categories_for_student($stud_id, $course_code, $session_id);
1641 View Code Duplication
            } else {
1642
                return Category::load(
1643
                    null,
1644
                    null,
1645
                    $course_code,
1646
                    $this->id,
1647
                    api_is_allowed_to_edit() ? null : 1,
1648
                    $session_id,
1649
                    $order
1650
                );
1651
            }
1652
        } else {
1653
            // All students
1654
            // Course admin
1655
            if (api_is_allowed_to_edit() && !api_is_platform_admin()) {
1656
1657
                // root
1658
                if ($this->id == 0) {
1659
                    return $this->get_root_categories_for_teacher(api_get_user_id(), $course_code, $session_id, false);
1660
                    // inside a course
1661
                } elseif (!empty($this->course_code)) {
1662
                    return Category::load(null, null, $this->course_code, $this->id, null, $session_id, $order);
1663 View Code Duplication
                } elseif (!empty($course_code)) {
1664
                    return Category::load(null, null, $course_code, $this->id, null, $session_id, $order);
1665
                    // course independent
1666
                } else {
1667
                    return Category::load(null, api_get_user_id(), 0, $this->id, null);
1668
                }
1669 View Code Duplication
            } elseif (api_is_platform_admin()) {
1670
                // platform admin
1671
                // we explicitly avoid listing subcats from another session
1672
                return Category::load(null, null, $course_code, $this->id, null, $session_id, $order);
1673
            }
1674
        }
1675
1676
        return array();
1677
    }
1678
1679
    /**
1680
     * Get appropriate evaluations visible for the user
1681
     * @param int $stud_id student id (default: all students)
1682
     * @param boolean $recursive process subcategories (default: no recursion)
1683
     * @param string $course_code
1684
     * @param int $sessionId
1685
     *
1686
     * @return array
1687
     */
1688
    public function get_evaluations(
1689
        $stud_id = null,
1690
        $recursive = false,
1691
        $course_code = '',
1692
        $sessionId = 0
1693
    ) {
1694
        $evals = array();
1695
1696
        if (empty($course_code)) {
1697
            $course_code = api_get_course_id();
1698
        }
1699
1700
        if (empty($sessionId)) {
1701
            $sessionId = api_get_session_id();
1702
        }
1703
1704
        // 1 student
1705
        if (isset($stud_id) && !empty($stud_id)) {
1706
            // Special case: this is the root
1707
            if ($this->id == 0) {
1708
                $evals = Evaluation::get_evaluations_with_result_for_student(0, $stud_id);
1709
            } else {
1710
                $evals = Evaluation::load(
1711
                    null,
1712
                    null,
1713
                    $course_code,
1714
                    $this->id,
1715
                    api_is_allowed_to_edit() ? null : 1
1716
                );
1717
            }
1718
        } else {
1719
            // All students
1720
            // course admin
1721
            if ((api_is_allowed_to_edit() || api_is_drh() || api_is_session_admin()) &&
1722
                !api_is_platform_admin()
1723
            ) {
1724
                // root
1725
                if ($this->id == 0) {
1726
                    $evals = Evaluation::load(null, api_get_user_id(), null, $this->id, null);
1727
                } elseif (isset($this->course_code) && !empty($this->course_code)) {
1728
                    // inside a course
1729
                    $evals = Evaluation::load(null, null, $course_code, $this->id, null);
1730
                } else {
1731
                    // course independent
1732
                    $evals = Evaluation::load(null, api_get_user_id(), null, $this->id, null);
1733
                }
1734
            } else {
1735
                $evals = Evaluation::load(null, null, $course_code, $this->id, null);
1736
            }
1737
        }
1738
1739 View Code Duplication
        if ($recursive) {
1740
            $subcats = $this->get_subcategories($stud_id, $course_code, $sessionId);
1741
1742
            if (!empty($subcats)) {
1743
                foreach ($subcats as $subcat) {
1744
                    $subevals = $subcat->get_evaluations($stud_id, true, $course_code);
1745
                    $evals = array_merge($evals, $subevals);
1746
                }
1747
            }
1748
        }
1749
1750
        return $evals;
1751
    }
1752
1753
    /**
1754
     * Get appropriate links visible for the user
1755
     * @param int $stud_id student id (default: all students)
1756
     * @param boolean $recursive process subcategories (default: no recursion)
1757
     * @param string $course_code
1758
     * @param int $sessionId
1759
     *
1760
     * @return array
1761
     */
1762
    public function get_links(
1763
        $stud_id = null,
1764
        $recursive = false,
1765
        $course_code = '',
1766
        $sessionId = 0
1767
    ) {
1768
        $links = array();
1769
1770
        if (empty($course_code)) {
1771
            $course_code = api_get_course_id();
1772
        }
1773
1774
        if (empty($sessionId)) {
1775
            $sessionId = api_get_session_id();
1776
        }
1777
1778
        // no links in root or course independent categories
1779
        if ($this->id == 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1780
        } elseif (isset($stud_id)) {
1781
            // 1 student $stud_id
1782
            $links = LinkFactory::load(
1783
                null,
1784
                null,
1785
                null,
1786
                null,
1787
                empty($this->course_code) ? null : $course_code,
1788
                $this->id,
1789
                api_is_allowed_to_edit() ? null : 1
1790
            );
1791
            //} elseif (api_is_allowed_to_edit() || api_is_drh() || api_is_session_admin()) {
1792
        } else {
1793
            // All students -> only for course/platform admin
1794
            $links = LinkFactory::load(
1795
                null,
1796
                null,
1797
                null,
1798
                null,
1799
                empty($this->course_code) ? null : $this->course_code,
1800
                $this->id,
1801
                null
1802
            );
1803
        }
1804
1805 View Code Duplication
        if ($recursive) {
1806
            $subcats = $this->get_subcategories(
1807
                $stud_id,
1808
                $course_code,
1809
                $sessionId
1810
            );
1811
            if (!empty($subcats)) {
1812
                /** @var Category $subcat */
1813
                foreach ($subcats as $subcat) {
1814
                    $sublinks = $subcat->get_links(
1815
                        $stud_id,
1816
                        false,
1817
                        $course_code,
1818
                        $sessionId
1819
                    );
1820
                    $links = array_merge($links, $sublinks);
1821
                }
1822
            }
1823
        }
1824
1825
        return $links;
1826
    }
1827
1828
    /**
1829
     * Get all the categories from with the same given direct parent
1830
     * @param int $catId Category parent ID
1831
     * @return array Array of Category objects
1832
     */
1833 View Code Duplication
    public function getCategories($catId)
1834
    {
1835
        $tblGradeCategories = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1836
        $sql = 'SELECT * FROM '.$tblGradeCategories.'
1837
                WHERE parent_id = '.intval($catId);
1838
1839
        $result = Database::query($sql);
1840
        $allcats = Category::create_category_objects_from_sql_result($result);
1841
1842
        return $allcats;
1843
    }
1844
1845
    /**
1846
     * Gets the type for the current object
1847
     * @return string 'C' to represent "Category" object type
1848
     */
1849
    public function get_item_type()
1850
    {
1851
        return 'C';
1852
    }
1853
1854
    /**
1855
     * @param array $skills
1856
     */
1857
    public function set_skills($skills)
1858
    {
1859
        $this->skills = $skills;
1860
    }
1861
1862
    /**
1863
     * @return null
1864
     */
1865
    public function get_date()
1866
    {
1867
        return null;
1868
    }
1869
1870
    /**
1871
     * @return string
1872
     */
1873
    public function get_icon_name()
1874
    {
1875
        return 'cat';
1876
    }
1877
1878
    /**
1879
     * Find category by name
1880
     * @param string $name_mask search string
1881
     * @return array category objects matching the search criterium
1882
     */
1883
    public function find_category($name_mask,$allcat)
1884
    {
1885
        $foundcats = array();
1886
        foreach ($allcat as $search_cat) {
1887
            if (!(strpos(strtolower($search_cat->get_name()), strtolower($name_mask)) === false)) {
1888
                $foundcats[] = $search_cat;
1889
            }
1890
        }
1891
1892
        return $foundcats;
1893
    }
1894
1895
    /**
1896
     * This function, locks a category , only one who can unlock it is
1897
     * the platform administrator.
1898
     * @param int locked 1 or unlocked 0
1899
1900
     * @return boolean|null
1901
     * */
1902 View Code Duplication
    public function lock($locked)
1903
    {
1904
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1905
        $sql = "UPDATE $table SET locked = '".intval($locked)."'
1906
                WHERE id='".intval($this->id)."'";
1907
        Database::query($sql);
1908
    }
1909
1910
    /**
1911
     * @param $locked
1912
     */
1913
    public function lock_all_items($locked)
1914
    {
1915
        if (api_get_setting('gradebook_locking_enabled') == 'true') {
1916
            $this->lock($locked);
1917
1918
            $evals_to_lock = $this->get_evaluations();
1919
1920
            if (!empty($evals_to_lock)) {
1921
                foreach ($evals_to_lock as $item) {
1922
                    $item->lock($locked);
1923
                }
1924
            }
1925
1926
            $link_to_lock= $this->get_links();
1927
            if (!empty($link_to_lock)) {
1928
                foreach ($link_to_lock as $item ) {
1929
                    $item->lock($locked);
1930
                }
1931
            }
1932
1933
            $event_type = LOG_GRADEBOOK_UNLOCKED;
1934
            if ($locked == 1) {
1935
                $event_type = LOG_GRADEBOOK_LOCKED;
1936
            }
1937
            Event::addEvent($event_type, LOG_GRADEBOOK_ID, $this->id);
1938
        }
1939
    }
1940
1941
    /**
1942
     * Generates a certificate for this user if everything matches
1943
     * @param int $category_id
1944
     * @param int $user_id
1945
     * @return bool|string
1946
     */
1947
    public static function register_user_certificate($category_id, $user_id)
1948
    {
1949
        $courseId = api_get_course_int_id();
1950
        $courseCode = api_get_course_id();
1951
        $sessionId = api_get_session_id();
1952
        // Generating the total score for a course
1953
        $cats_course = Category::load(
1954
            $category_id,
1955
            null,
1956
            null,
1957
            null,
1958
            null,
1959
            $sessionId,
1960
            false
1961
        );
1962
1963
        /** @var Category $category */
1964
        $category = $cats_course[0];
1965
1966
        //@todo move these in a function
1967
        $sum_categories_weight_array = array();
1968
        if (isset($cats_course) && !empty($cats_course)) {
1969
            $categories = Category::load(null, null, null, $category_id);
1970
            if (!empty($categories)) {
1971
                foreach ($categories as $subCategory) {
1972
                    $sum_categories_weight_array[$subCategory->get_id()] = $subCategory->get_weight();
1973
                }
1974
            } else {
1975
                $sum_categories_weight_array[$category_id] = $cats_course[0]->get_weight();
1976
            }
1977
        }
1978
1979
        $main_weight = $cats_course[0]->get_weight();
1980
1981
        $cattotal = Category::load($category_id);
1982
        $scoretotal = $cattotal[0]->calc_score($user_id);
1983
1984
        // Do not remove this the gradebook/lib/fe/gradebooktable.class.php
1985
        // file load this variable as a global
1986
        $scoredisplay = ScoreDisplay::instance();
1987
        $my_score_in_gradebook = $scoredisplay->display_score($scoretotal, SCORE_SIMPLE);
1988
1989
        // A student always sees only the teacher's repartition
1990
        $scoretotal_display = $scoredisplay->display_score($scoretotal, SCORE_DIV_PERCENT);
1991
1992
        if (!self::userFinishedCourse($user_id, $cats_course[0], 0, $courseCode, $sessionId, true)) {
1993
            return false;
1994
        }
1995
1996
        $skillToolEnabled = api_get_setting('allow_skills_tool') == 'true';
1997
        $userHasSkills = false;
1998
1999
        if ($skillToolEnabled) {
2000
            $skill = new Skill();
2001
            $skill->add_skill_to_user(
2002
                $user_id,
2003
                $category_id,
2004
                $courseId,
2005
                $sessionId
2006
            );
2007
2008
            $objSkillRelUser = new SkillRelUser();
2009
            $userSkills = $objSkillRelUser->get_user_skills($user_id, $courseId, $sessionId);
2010
            $userHasSkills = !empty($userSkills);
2011
2012 View Code Duplication
            if (!$category->getGenerateCertificates() && $userHasSkills) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $category->getGenerateCertificates() of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2013
                return [
2014
                    'badge_link' => Display::toolbarButton(
2015
                        get_lang('ExportBadges'),
2016
                        api_get_path(WEB_CODE_PATH) . "gradebook/get_badges.php?user=$user_id",
2017
                        'external-link'
2018
                    )
2019
                ];
2020
            }
2021
        }
2022
2023
        $my_certificate = GradebookUtils::get_certificate_by_user_id(
2024
            $cats_course[0]->get_id(),
2025
            $user_id
2026
        );
2027
2028
        if (empty($my_certificate)) {
2029
            GradebookUtils::registerUserInfoAboutCertificate(
2030
                $category_id,
2031
                $user_id,
2032
                $my_score_in_gradebook,
2033
                api_get_utc_datetime()
0 ignored issues
show
Bug introduced by
It seems like api_get_utc_datetime() can also be of type null or object<DateTime>; however, GradebookUtils::registerUserInfoAboutCertificate() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
2034
            );
2035
            $my_certificate = GradebookUtils::get_certificate_by_user_id(
2036
                $cats_course[0]->get_id(),
2037
                $user_id
2038
            );
2039
        }
2040
2041
        $html = array();
2042
        if (!empty($my_certificate)) {
2043
            $certificate_obj = new Certificate($my_certificate['id']);
2044
            $fileWasGenerated = $certificate_obj->html_file_is_generated();
2045
2046
            if (!empty($fileWasGenerated)) {
2047
                $url = api_get_path(WEB_PATH) . 'certificates/index.php?id=' . $my_certificate['id'];
2048
2049
                $certificates = Display::toolbarButton(get_lang('DisplayCertificate'), $url, 'eye', 'primary');
2050
2051
                $exportToPDF = Display::url(
2052
                    Display::return_icon(
2053
                        'pdf.png',
2054
                        get_lang('ExportToPDF'),
2055
                        array(),
2056
                        ICON_SIZE_MEDIUM
2057
                    ),
2058
                    "$url&action=export"
2059
                );
2060
2061
                $hideExportLink = api_get_setting('hide_certificate_export_link');
2062
                $hideExportLinkStudent = api_get_setting('hide_certificate_export_link_students');
2063
                if ($hideExportLink === 'true' || (api_is_student() && $hideExportLinkStudent === 'true') ) {
2064
                    $exportToPDF = null;
2065
                }
2066
2067
                $html = array(
2068
                    'certificate_link' => $certificates,
2069
                    'pdf_link' => $exportToPDF,
2070
                    'pdf_url' => "$url&action=export"
2071
                );
2072
2073 View Code Duplication
                if ($skillToolEnabled && $userHasSkills) {
2074
                    $html['badge_link'] = Display::toolbarButton(
2075
                        get_lang('ExportBadges'),
2076
                        api_get_path(WEB_CODE_PATH) . "gradebook/get_badges.php?user=$user_id",
2077
                        'external-link'
2078
                    );
2079
                }
2080
            }
2081
            return $html;
2082
        }
2083
    }
2084
2085
    /**
2086
     * @param int $catId
2087
     * @param array $userList
2088
     */
2089
    public static function generateCertificatesInUserList($catId, $userList)
2090
    {
2091
        if (!empty($userList)) {
2092
            foreach ($userList as $userInfo) {
2093
                self::register_user_certificate($catId, $userInfo['user_id']);
2094
            }
2095
        }
2096
    }
2097
2098
    /**
2099
     * @param int $catId
2100
     * @param array $userList
2101
     */
2102
    public static function exportAllCertificates(
2103
        $catId,
2104
        $userList = array()
2105
    ) {
2106
        $orientation = api_get_configuration_value('certificate_pdf_orientation');
2107
2108
        $params['orientation'] = 'landscape';
2109
        if (!empty($orientation)) {
2110
            $params['orientation'] = $orientation;
2111
        }
2112
2113
        $params['left'] = 0;
2114
        $params['right'] = 0;
2115
        $params['top'] = 0;
2116
        $params['bottom'] = 0;
2117
        $page_format = $params['orientation'] == 'landscape' ? 'A4-L' : 'A4';
2118
        $pdf = new PDF($page_format, $params['orientation'], $params);
2119
2120
        $certificate_list = GradebookUtils::get_list_users_certificates($catId, $userList);
2121
        $certificate_path_list = array();
2122
2123
        if (!empty($certificate_list)) {
2124
            foreach ($certificate_list as $index=>$value) {
2125
                $list_certificate = GradebookUtils::get_list_gradebook_certificates_by_user_id(
2126
                    $value['user_id'],
2127
                    $catId
2128
                );
2129
                foreach ($list_certificate as $value_certificate) {
2130
                    $certificate_obj = new Certificate($value_certificate['id']);
2131
                    $certificate_obj->generate(array('hide_print_button' => true));
2132
                    if ($certificate_obj->html_file_is_generated()) {
2133
                        $certificate_path_list[]= $certificate_obj->html_file;
2134
                    }
2135
                }
2136
            }
2137
        }
2138
2139
        if (!empty($certificate_path_list)) {
2140
            // Print certificates (without the common header/footer/watermark
2141
            //  stuff) and return as one multiple-pages PDF
2142
            $pdf->html_to_pdf(
2143
                $certificate_path_list,
2144
                get_lang('Certificates'),
2145
                null,
2146
                false,
2147
                false
2148
            );
2149
        }
2150
    }
2151
2152
    /**
2153
     * @param int $catId
2154
     */
2155
    public static function deleteAllCertificates($catId)
2156
    {
2157
        $certificate_list = GradebookUtils::get_list_users_certificates($catId);
2158
        if (!empty($certificate_list)) {
2159
            foreach ($certificate_list as $index=>$value) {
2160
                $list_certificate = GradebookUtils::get_list_gradebook_certificates_by_user_id($value['user_id'], $catId);
2161
                foreach ($list_certificate as $value_certificate) {
2162
                    $certificate_obj = new Certificate($value_certificate['id']);
2163
                    $certificate_obj->delete(true);
2164
                }
2165
            }
2166
        }
2167
    }
2168
2169
    /**
2170
     * Check whether a user has finished a course by its gradebook
2171
     * @param int $userId The user ID
2172
     * @param \Category $category Optional. The gradebook category.
2173
     *         To check by the gradebook category
2174
     * @param int $categoryId Optional. The gradebook category ID.
2175
     *         To check by the category ID
2176
     * @param string $courseCode Optional. The course code
2177
     * @param int $sessionId Optional. The session ID
2178
     * @param boolean $recalcutateScore Whether recalculate the score
2179
     * @return boolean
2180
     */
2181
    public static function userFinishedCourse(
2182
        $userId,
2183
        \Category $category = null,
2184
        $categoryId = 0,
2185
        $courseCode = null,
2186
        $sessionId = 0,
2187
        $recalcutateScore = false
2188
    ) {
2189
        if (is_null($category) && empty($categoryId)) {
2190
            return false;
2191
        }
2192
2193
        $courseCode = empty($courseCode) ? api_get_course_id() : $courseCode;
2194
        $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
2195
2196
        if (is_null($category) && !empty($categoryId)) {
2197
            $cats_course = Category::load(
2198
                $categoryId,
2199
                null,
2200
                $courseCode,
2201
                null,
2202
                null,
2203
                $sessionId,
2204
                false
2205
            );
2206
2207
            if (empty($cats_course)) {
2208
                return false;
2209
            }
2210
2211
            $category = $cats_course[0];
2212
        }
2213
2214
        $currentScore = self::getCurrentScore(
2215
            $userId,
2216
            $category->get_id(),
2217
            $courseCode,
2218
            $sessionId,
2219
            $recalcutateScore
2220
        );
2221
2222
        $minCertificateScore = $category->get_certificate_min_score();
2223
2224
        return !empty($minCertificateScore) && $currentScore >= $minCertificateScore;
2225
    }
2226
2227
    /**
2228
     * Get the current score (as percentage) on a gradebook category for a user
2229
     * @param int $userId The user id
2230
     * @param int $categoryId The gradebook category
2231
     * @param int $courseCode The course code
2232
     * @param int $sessionId Optional. The session id
2233
     * @param bool $recalculate
2234
     *
2235
     * @return float The score
2236
     */
2237
    public static function getCurrentScore($userId, $categoryId, $courseCode, $sessionId = 0, $recalculate = false)
2238
    {
2239
        if ($recalculate) {
2240
            return self::calculateCurrentScore($userId, $categoryId, $courseCode, $sessionId);
2241
        }
2242
2243
        $resultData = Database::select(
2244
            '*',
2245
            Database::get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_LOG),
2246
            [
2247
                'where' => [
2248
                    'category_id = ? AND user_id = ?' => [$categoryId, $userId],
2249
                ],
2250
                'order' => 'registered_at DESC',
2251
                'limit' => '1'
2252
            ],
2253
            'first'
2254
        );
2255
2256
        if (empty($resultData)) {
2257
            return 0;
2258
        }
2259
2260
        return $resultData['score'];
2261
    }
2262
2263
    /**
2264
     * Calculate the current score on a gradebook category for a user
2265
     * @param int $userId The user id
2266
     * @param int $categoryId The gradebook category
2267
     * @param int $courseCode The course code
2268
     * @param int $sessionId Optional. The session id
2269
     * @return float The score
2270
     */
2271
    private static function calculateCurrentScore($userId, $categoryId, $courseCode, $sessionId)
2272
    {
2273
        $cats_course = Category::load(
2274
            $categoryId,
2275
            null,
2276
            $courseCode,
2277
            null,
2278
            null,
2279
            $sessionId,
2280
            false
2281
        );
2282
2283
        if (empty($cats_course)) {
2284
            return 0;
2285
        }
2286
2287
        $category = $cats_course[0];
2288
2289
        $courseEvaluations = $category->get_evaluations($userId, true);
2290
        $courseLinks = $category->get_links($userId, true);
2291
2292
        $evaluationsAndLinks = array_merge($courseEvaluations, $courseLinks);
2293
2294
        $categoryScore = 0;
2295
2296
        for ($i = 0; $i < count($evaluationsAndLinks); $i++) {
2297
            $item = $evaluationsAndLinks[$i];
2298
            $score = $item->calc_score($userId);
2299
            $itemValue = 0;
2300
2301
            if (!empty($score)) {
2302
                $divider = $score[1] == 0 ? 1 : $score[1];
2303
                $itemValue = $score[0] / $divider * $item->get_weight();
2304
            }
2305
2306
            $categoryScore += $itemValue;
2307
        }
2308
2309
        return floatval($categoryScore);
2310
    }
2311
2312
    /**
2313
     * Register the current score for a user on a category gradebook
2314
     * @param float $score The achieved score
2315
     * @param int $userId The user id
2316
     * @param int $categoryId The gradebook category
2317
     * @return false|string The insert id
2318
     */
2319
    public static function registerCurrentScore($score, $userId, $categoryId)
2320
    {
2321
        return Database::insert(
2322
            Database::get_main_table(TABLE_MAIN_GRADEBOOK_SCORE_LOG),
2323
            [
2324
                'category_id' => intval($categoryId),
2325
                'user_id' => intval($userId),
2326
                'score' => floatval($score),
2327
                'registered_at' => api_get_utc_datetime()
2328
            ]
2329
        );
2330
    }
2331
2332
    /**
2333
     * @return array
2334
     */
2335
    public function getStudentList()
2336
    {
2337
        return $this->studentList;
2338
    }
2339
2340
    /**
2341
     * @param array $list
2342
     */
2343
    public function setStudentList($list)
2344
    {
2345
        $this->studentList = $list;
2346
    }
2347
2348
    /**
2349
     * @return int
2350
     */
2351
    public function getCourseId()
2352
    {
2353
        return $this->courseId;
2354
    }
2355
2356
    /**
2357
     * @param int $courseId
2358
     * @return Category
2359
     */
2360
    public function setCourseId($courseId)
2361
    {
2362
        $this->courseId = $courseId;
2363
2364
        return $this;
2365
    }
2366
2367
}
2368