Completed
Push — 1.11.x ( 033bfd...c69862 )
by José
141:38 queued 100:32
created

Skill::get_skills_tree_json()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
cc 3
eloc 9
c 2
b 2
f 0
nc 2
nop 4
dl 0
loc 15
rs 9.4285
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Class SkillProfile
6
 * @package chamilo.library
7
 */
8
class SkillProfile extends Model
9
{
10
    public $columns = array('id', 'name', 'description');
11
12
    /**
13
     * Constructor
14
     */
15
    public function __construct()
16
    {
17
        $this->table = Database::get_main_table(TABLE_MAIN_SKILL_PROFILE);
18
        $this->table_rel_profile = Database::get_main_table(TABLE_MAIN_SKILL_REL_PROFILE);
19
    }
20
21
    /**
22
     * @return array
23
     */
24
    public function get_profiles()
25
    {
26
        $sql = "SELECT * FROM $this->table p
27
                INNER JOIN $this->table_rel_profile sp
28
                ON(p.id = sp.profile_id) ";
29
        $result   = Database::query($sql);
30
        $profiles = Database::store_result($result, 'ASSOC');
31
32
        return $profiles;
33
    }
34
35
    /**
36
    * This function is for editing profile info from profile_id.
37
    * @param int    $profileId
38
    * @param string $name
39
    * @param string $description
40
    */
41
    public function updateProfileInfo($profileId, $name, $description)
42
    {
43
        $profileId = intval($profileId);
44
        $sql = "UPDATE $this->table SET
45
                    name = '$name',
46
                    description = '$description'
47
                WHERE id = $profileId ";
48
        $result = Database::query($sql);
49
50
        return $result;
51
    }
52
53
    /**
54
     * Call the save method of the parent class and the SkillRelProfile object
55
     * @param array Params
56
     * @param bool Whether to show the query in parent save() method
57
     * @return mixed Profile ID or false if incomplete params
58
     */
59
    public function save($params, $show_query = false)
60
    {
61
        if (!empty($params)) {
62
            $profile_id = parent::save($params, $show_query);
63
            if ($profile_id) {
64
                $skill_rel_profile = new SkillRelProfile();
65
                if (isset($params['skills'])) {
66
                    foreach ($params['skills'] as $skill_id) {
67
                        $attributes = array('skill_id' => $skill_id, 'profile_id' => $profile_id);
68
                        $skill_rel_profile->save($attributes);
69
                    }
70
                }
71
                return $profile_id;
72
            }
73
        }
74
75
        return false;
76
    }
77
78
    /**
79
     * Delete a skill profile
80
     * @param int $id The skill profile id
81
     * @return boolean Whether delete a skill profile
82
     */
83
    public function delete($id)
84
    {
85
        Database::delete(
86
            $this->table_rel_profile,
87
            array(
88
                'profile_id' => $id
89
            )
90
        );
91
92
        return parent::delete($id);
93
    }
94
}
95
96
/**
97
 * Class SkillRelProfile
98
 */
99
class SkillRelProfile extends Model
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
100
{
101
    public $columns = array('id', 'skill_id', 'profile_id');
102
103
    /**
104
     * Constructor
105
     */
106
    public function __construct()
107
    {
108
        $this->table = Database::get_main_table(TABLE_MAIN_SKILL_REL_PROFILE);
109
        $this->tableProfile = Database::get_main_table(TABLE_MAIN_SKILL_PROFILE);
110
    }
111
112
    /**
113
     * @param int $profileId
114
     * @return array
115
     */
116
    public function get_skills_by_profile($profileId)
117
    {
118
        $profileId = intval($profileId);
119
        $skills = $this->get_all(array('where' => array('profile_id = ? ' => $profileId)));
120
        $return = array();
121
        if (!empty($skills)) {
122
            foreach ($skills as $skill_data) {
123
                $return[] = $skill_data['skill_id'];
124
            }
125
        }
126
127
        return $return;
128
    }
129
130
    /**
131
    * This function is for getting profile info from profile_id.
132
    * @param int $profileId
133
    */
134
135 View Code Duplication
    public function getProfileInfo($profileId)
136
    {
137
        $sql = "SELECT * FROM $this->table p
138
                INNER JOIN $this->tableProfile pr
139
                ON (pr.id = p.profile_id)
140
                WHERE p.profile_id = ".intval($profileId);
141
        $result = Database::query($sql);
142
        $profileData = Database::fetch_array($result, 'ASSOC');
143
144
        return $profileData;
145
    }
146
}
147
148
/**
149
 * Class SkillRelSkill
150
 */
151
class SkillRelSkill extends Model
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
152
{
153
    public $columns = array('skill_id', 'parent_id', 'relation_type', 'level');
154
155
    /**
156
     * Constructor
157
     */
158
    public function __construct()
159
    {
160
        $this->table = Database::get_main_table(TABLE_MAIN_SKILL_REL_SKILL);
161
    }
162
163
    /**
164
     * Gets an element
165
     * @param int $id
166
     * @return array
167
     */
168 View Code Duplication
    public function get_skill_info($id)
169
    {
170
        if (empty($id)) {
171
            return array();
172
        }
173
        $result = Database::select(
174
            '*',
175
            $this->table,
176
            array('where' => array('skill_id = ?' => intval($id))),
177
            'first'
178
        );
179
180
        return $result;
181
    }
182
183
    public function get_skill_parents($skill_id, $add_child_info = true)
184
    {
185
        $skill_id = intval($skill_id);
186
        $sql = 'SELECT child.* FROM '.$this->table.' child
187
                LEFT JOIN '.$this->table.' parent
188
                ON child.parent_id = parent.skill_id
189
                WHERE child.skill_id = '.$skill_id.' ';
190
        $result = Database::query($sql);
191
        $skill = Database::store_result($result, 'ASSOC');
192
        $skill = isset($skill[0]) ? $skill[0] : null;
193
194
        $parents = array();
195
        if (!empty($skill)) {
196
            if ($skill['parent_id'] != null) {
197
                $parents = self::get_skill_parents($skill['parent_id']);
198
            }
199
            if ($add_child_info) {
200
                $parents[] = $skill;
201
            }
202
        }
203
        return $parents;
204
    }
205
206
    /**
207
     * @param int $skill_id
208
     * @return array
209
     */
210
    public function get_direct_parents($skill_id)
211
    {
212
        $skill_id = intval($skill_id);
213
        $sql      = 'SELECT parent_id as skill_id FROM '.$this->table.'
214
                     WHERE skill_id = '.$skill_id.' ';
215
        $result   = Database::query($sql);
216
        $skill    = Database::store_result($result, 'ASSOC');
217
        $skill    = isset($skill[0]) ? $skill[0] : null;
218
        $parents  = array();
219
        if (!empty($skill)) {
220
            $parents[] = $skill;
221
        }
222
223
        return $parents;
224
    }
225
226
    /**
227
     * @param int $skill_id
228
     * @param bool $load_user_data
229
     * @param bool $user_id
230
     * @return array
231
     */
232
    public function get_children($skill_id, $load_user_data = false, $user_id = false)
233
    {
234
        $skills = $this->find('all', array('where' => array('parent_id = ? ' => $skill_id)));
235
        $skill_obj = new Skill();
236
        $skill_rel_user = new SkillRelUser();
237
238
        if ($load_user_data) {
239
            $passed_skills = $skill_rel_user->get_user_skills($user_id);
240
            $done_skills   = array();
241
            foreach ($passed_skills as $done_skill) {
242
                $done_skills[] = $done_skill['skill_id'];
243
            }
244
        }
245
246
        if (!empty($skills)) {
247
            foreach ($skills as &$skill) {
248
                $skill['data'] = $skill_obj->get($skill['skill_id']);
249
                if (isset($skill['data']) && !empty($skill['data'])) {
250
                    if (!empty($done_skills)) {
251
                        $skill['data']['passed'] = 0;
252
                        if (in_array($skill['skill_id'], $done_skills)) {
253
                            $skill['data']['passed'] = 1;
254
                        }
255
                    }
256
                } else {
257
                    $skill = null;
258
                }
259
            }
260
        }
261
262
        return $skills;
263
    }
264
265
    /**
266
     * @param array $params
267
     * @return bool
268
     */
269
    public function update_by_skill($params)
270
    {
271
        $result = Database::update($this->table, $params, array('skill_id = ? ' => $params['skill_id']));
272
        if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type integer|false is loosely compared to true; 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...
273
            return true;
274
        }
275
276
        return false;
277
    }
278
279
    /**
280
     * @param int $skill_id
281
     * @param int $parent_id
282
     * @return bool
283
     */
284 View Code Duplication
    public function relation_exists($skill_id, $parent_id)
285
    {
286
        $result = $this->find(
287
            'all',
288
            array('where' => array('skill_id = ? AND parent_id = ?' => array($skill_id, $parent_id)))
289
        );
290
291
        if (!empty($result)) {
292
            return true;
293
        }
294
        return false;
295
    }
296
}
297
298
/**
299
 * Class SkillRelGradebook
300
 */
301
class SkillRelGradebook extends Model
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
302
{
303
    public $columns = array('id', 'gradebook_id', 'skill_id');
304
305
    public function __construct()
306
    {
307
        $this->table = Database::get_main_table(TABLE_MAIN_SKILL_REL_GRADEBOOK);
308
    }
309
310
    /**
311
     * @param int $gradebook_id
312
     * @param int $skill_id
313
     * @return bool
314
     */
315 View Code Duplication
    public function exists_gradebook_skill($gradebook_id, $skill_id)
316
    {
317
        $result = $this->find(
318
            'all',
319
            array('where' => array('gradebook_id = ? AND skill_id = ?' => array($gradebook_id, $skill_id)))
320
        );
321
        if (!empty($result)) {
322
            return true;
323
        }
324
        return false;
325
    }
326
327
    /**
328
     * Gets an element
329
     */
330 View Code Duplication
    public function get_skill_info($skill_id, $gradebook_id)
331
    {
332
        if (empty($skill_id)) {
333
            return array();
334
        }
335
        $result = Database::select(
336
            '*',
337
            $this->table,
338
            array('where' => array('skill_id = ? AND gradebook_id = ? ' => array($skill_id, $gradebook_id))),
339
            'first'
340
        );
341
        return $result;
342
    }
343
344
    /**
345
     * @param int $skill_id
346
     * @param array $gradebook_list
347
     */
348
    public function update_gradebooks_by_skill($skill_id, $gradebook_list)
349
    {
350
        $original_gradebook_list = $this->find(
351
            'all',
352
            array('where' => array('skill_id = ?' => array($skill_id)))
353
        );
354
        $gradebooks_to_remove = array();
355
        $gradebooks_to_add = array();
356
        $original_gradebook_list_ids = array();
357
358
        if (!empty($original_gradebook_list)) {
359
            foreach ($original_gradebook_list as $gradebook) {
360
                if (!in_array($gradebook['gradebook_id'], $gradebook_list)) {
361
                    $gradebooks_to_remove[] = $gradebook['id'];
362
                }
363
            }
364
            foreach ($original_gradebook_list as $gradebook_item) {
365
                $original_gradebook_list_ids[] = $gradebook_item['gradebook_id'];
366
            }
367
        }
368
369
        if (!empty($gradebook_list)) {
370
            foreach ($gradebook_list as $gradebook_id) {
371
                if (!in_array($gradebook_id, $original_gradebook_list_ids)) {
372
                    $gradebooks_to_add[] = $gradebook_id;
373
                }
374
            }
375
        }
376
377
        if (!empty($gradebooks_to_remove)) {
378
            foreach ($gradebooks_to_remove as $id) {
379
                $this->delete($id);
380
            }
381
        }
382
383
        if (!empty($gradebooks_to_add)) {
384
            foreach ($gradebooks_to_add as $gradebook_id) {
385
                $attributes = array('skill_id' => $skill_id, 'gradebook_id' => $gradebook_id);
386
                $this->save($attributes);
387
            }
388
        }
389
    }
390
391
    /**
392
     * @param array $params
393
     * @return bool|void
394
     */
395
    public function update_by_skill($params)
396
    {
397
        $skill_info = $this->exists_gradebook_skill($params['gradebook_id'], $params['skill_id']);
398
399
        if ($skill_info) {
400
            return;
401
        } else {
402
            $result = $this->save($params);
403
        }
404
        if ($result) {
405
            return true;
406
        }
407
        return false;
408
    }
409
}
410
411
/**
412
 * Class SkillRelUser
413
 */
414
class SkillRelUser extends Model
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
415
{
416
    public $columns = array('id', 'user_id', 'skill_id', 'acquired_skill_at', 'assigned_by', 'course_id', 'session_id');
417
418
    /**
419
     * Constructor
420
     */
421
    public function __construct()
422
    {
423
        $this->table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
424
    }
425
426
    /**
427
     * @param array $skill_list
428
     * @return array
429
     */
430 View Code Duplication
    public function get_user_by_skills($skill_list)
431
    {
432
        $users = array();
433
        if (!empty($skill_list)) {
434
            $skill_list = array_map('intval', $skill_list);
435
            $skill_list = implode("', '", $skill_list);
436
437
            $sql = "SELECT user_id FROM {$this->table}
438
                    WHERE skill_id IN ('$skill_list') ";
439
440
            $result = Database::query($sql);
441
            $users  = Database::store_result($result, 'ASSOC');
442
        }
443
        return $users;
444
    }
445
446
    /**
447
     * Get the achieved skills for the user
448
     * @param int $userId
449
     * @param int $courseId Optional. The course id
450
     * @param int $sessionId Optional. The session id
451
     * @return array The skill list. Otherwise return false
452
     */
453
    public function get_user_skills($userId, $courseId = 0, $sessionId = 0)
454
    {
455
        if (empty($userId)) {
456
            return array();
457
        }
458
459
        $courseId = intval($courseId);
460
        $sessionId = $sessionId ? intval($sessionId) : null;
461
462
        $whereConditions = array(
463
            'user_id = ? ' => intval($userId)
464
        );
465
466
        if ($courseId > 0) {
467
            $whereConditions['AND course_id = ? '] = $courseId;
468
            $whereConditions['AND session_id = ?'] = $sessionId;
469
        }
470
471
        $result = Database::select(
472
            'skill_id',
473
            $this->table,
474
            array(
475
                'where' => $whereConditions
476
            ),
477
            'all'
478
        );
479
        return $result;
480
    }
481
482
    /**
483
     * Get the relation data between user and skill
484
     * @param int $userId The user id
485
     * @param int $skillId The skill id
486
     * @param int $courseId The course id
487
     * @param int $sessionId Optional. The session id
488
     * @return array The relation data. Otherwise return false
489
     */
490
    public function getByUserAndSkill($userId, $skillId, $courseId, $sessionId = 0)
491
    {
492
        $where = array(
493
            'user_id = ? AND skill_id = ? AND course_id = ? AND session_id = ?' => array(
494
                intval($userId),
495
                intval($skillId),
496
                intval($courseId),
497
                $sessionId ? intval($sessionId) : null
498
            )
499
        );
500
501
        return Database::select('*', $this->table, array(
502
            'where' => $where
503
        ), 'first');
504
    }
505
506
}
507
508
/**
509
 * Class Skill
510
 */
511
class Skill extends Model
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
512
{
513
    public $columns = array('id', 'name', 'description', 'access_url_id', 'short_code', 'icon', 'criteria');
514
    public $required = array('name');
515
516
    /** Array of colours by depth, for the coffee wheel. Each depth has 4 col */
517
    /*var $colours = array(
518
      0 => array('#f9f0ab', '#ecc099', '#e098b0', '#ebe378'),
519
      1 => array('#d5dda1', '#4a5072', '#8dae43', '#72659d'),
520
      2 => array('#b28647', '#2e6093', '#393e64', '#1e8323'),
521
      3 => array('#9f6652', '#9f6652', '#9f6652', '#9f6652'),
522
      4 => array('#af643c', '#af643c', '#af643c', '#af643c'),
523
      5 => array('#72659d', '#72659d', '#72659d', '#72659d'),
524
      6 => array('#8a6e9e', '#8a6e9e', '#8a6e9e', '#8a6e9e'),
525
      7 => array('#92538c', '#92538c', '#92538c', '#92538c'),
526
      8 => array('#2e6093', '#2e6093', '#2e6093', '#2e6093'),
527
      9 => array('#3a5988', '#3a5988', '#3a5988', '#3a5988'),
528
     10 => array('#393e64', '#393e64', '#393e64', '#393e64'),
529
    );*/
530
531
    public function __construct()
532
    {
533
        $this->table = Database::get_main_table(TABLE_MAIN_SKILL);
534
        $this->table_user = Database::get_main_table(TABLE_MAIN_USER);
535
        $this->table_skill_rel_gradebook = Database::get_main_table(TABLE_MAIN_SKILL_REL_GRADEBOOK);
536
        $this->table_skill_rel_user = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
537
        $this->table_course = Database::get_main_table(TABLE_MAIN_COURSE);
538
        $this->table_skill_rel_skill = Database::get_main_table(TABLE_MAIN_SKILL_REL_SKILL);
539
        $this->table_gradebook = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
540
        $this->sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
541
    }
542
543
    /**
544
     * Gets an element
545
     * @param int $id
546
     *
547
     * @return array|mixed
548
     */
549
    public function get($id)
550
    {
551
        $result = parent::get($id);
552
        $result['web_icon_path'] = api_get_path(WEB_UPLOAD_PATH).'badges/'.$result['icon'];
553
554
        return $result;
555
    }
556
557
    /**
558
     * @param int $id
559
     * @return array
560
     */
561
    public function get_skill_info($id)
562
    {
563
        $skill_rel_skill = new SkillRelSkill();
564
        $skill_info = $this->get($id);
565
        if (!empty($skill_info)) {
566
            $skill_info['extra']      = $skill_rel_skill->get_skill_info($id);
567
            $skill_info['gradebooks'] = self::get_gradebooks_by_skill($id);
568
        }
569
        return $skill_info;
570
    }
571
572
    /**
573
     * @param array $skill_list
574
     * @return array
575
     */
576
    public function get_skills_info($skill_list)
577
    {
578
        $skill_list = array_map('intval', $skill_list);
579
        $skill_list = implode("', '", $skill_list);
580
581
        $sql = "SELECT * FROM {$this->table}  WHERE id IN ('$skill_list') ";
582
583
        $result = Database::query($sql);
584
        $users  = Database::store_result($result, 'ASSOC');
585
586
        foreach ($users as &$user) {
587
            if (!$user['icon']) {
588
                continue;
589
            }
590
591
            $user['icon_small'] = sprintf("badges/%s-small.png", sha1($user['name']));
592
        }
593
594
        return $users;
595
    }
596
597
    /**
598
     * @param bool $load_user_data
599
     * @param bool $user_id
600
     * @param int $id
601
     * @param int $parent_id
602
     * @return array
603
     */
604
    public function get_all($load_user_data = false, $user_id = false, $id = null, $parent_id = null)
605
    {
606
        $id_condition = '';
607
        if (!empty($id)) {
608
            $id = intval($id);
609
            $id_condition = " WHERE s.id = $id";
610
        }
611
612
        if (!empty($parent_id)) {
613
            $parent_id = intval($parent_id);
614
            if (empty($id_condition)) {
615
                $id_condition = " WHERE ss.parent_id = $parent_id";
616
            } else {
617
                $id_condition = " AND ss.parent_id = $parent_id";
618
            }
619
        }
620
621
        $sql = "SELECT
622
                    s.id,
623
                    s.name,
624
                    s.description,
625
                    ss.parent_id,
626
                    ss.relation_type,
627
                    s.icon,
628
                    s.short_code,
629
                    s.status
630
                FROM {$this->table} s
631
                INNER JOIN {$this->table_skill_rel_skill} ss
632
                ON (s.id = ss.skill_id) $id_condition
633
                ORDER BY ss.id, ss.parent_id";
634
635
        $result = Database::query($sql);
636
        $skills = array();
637
        $webPath = api_get_path(WEB_UPLOAD_PATH);
638
        if (Database::num_rows($result)) {
639
            while ($row = Database::fetch_array($result, 'ASSOC')) {
640
                $skill_rel_skill = new SkillRelSkill();
641
                $parents = $skill_rel_skill->get_skill_parents($row['id']);
642
                $row['level'] = count($parents) - 1;
643
                $row['gradebooks'] = self::get_gradebooks_by_skill($row['id']);
644
                $row['web_icon_path'] = $webPath.'badges/'.$row['icon'];
645
                $skills[$row['id']] = $row;
646
            }
647
        }
648
649
        // Load all children of the parent_id
650
        if (!empty($skills) && !empty($parent_id)) {
651
            foreach ($skills as $skill) {
652
                $children = self::get_all($load_user_data, $user_id, $id, $skill['id']);
653
                if (!empty($children)) {
654
                    //$skills = array_merge($skills, $children);
655
                    $skills = $skills + $children;
656
                }
657
            }
658
        }
659
        return $skills;
660
    }
661
662
    /**
663
     * @param int $skill_id
664
     * @return array|resource
665
     */
666 View Code Duplication
    public function get_gradebooks_by_skill($skill_id)
667
    {
668
        $skill_id = intval($skill_id);
669
        $sql = "SELECT g.* FROM {$this->table_gradebook} g
670
                INNER JOIN {$this->table_skill_rel_gradebook} sg
671
                    ON g.id = sg.gradebook_id
672
                 WHERE sg.skill_id = $skill_id";
673
        $result = Database::query($sql);
674
        $result = Database::store_result($result, 'ASSOC');
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, store_result() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
675
        return $result;
676
    }
677
678
    /**
679
     * Get one level childrens
680
     *
681
     * @param int $skill_id
682
     * @param bool $load_user_data
683
     * @return array
684
     */
685
    public function get_children($skill_id, $load_user_data = false)
686
    {
687
        $skill_rel_skill = new SkillRelSkill();
688
        if ($load_user_data) {
689
            $user_id = api_get_user_id();
690
            $skills  = $skill_rel_skill->get_children($skill_id, true, $user_id);
691
        } else {
692
            $skills = $skill_rel_skill->get_children($skill_id);
693
        }
694
        return $skills;
695
    }
696
697
    /**
698
     * Get all children of the current node (recursive)
699
     * @param int $skillId
700
     * @return array
701
     */
702
    public function get_all_children($skillId)
703
    {
704
        $skill_rel_skill = new SkillRelSkill();
705
        $children = $skill_rel_skill->get_children($skillId);
706
        foreach ($children as $child) {
0 ignored issues
show
Bug introduced by
The expression $children 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...
707
            $subChildren = $this->get_all_children($child['skill_id']);
708
        }
709
710
        if (!empty($subChildren)) {
711
            $children = array_merge($children, $subChildren);
712
        }
713
714
        return $children;
715
    }
716
717
    /**
718
     * Gets all parents from from the wanted skill
719
     */
720
    public function get_parents($skill_id)
721
    {
722
        $skill_rel_skill = new SkillRelSkill();
723
        $skills = $skill_rel_skill->get_skill_parents($skill_id, true);
724
        foreach ($skills as &$skill) {
725
            $skill['data'] = self::get($skill['skill_id']);
726
        }
727
        return $skills;
728
    }
729
730
    /**
731
     * All direct parents
732
     */
733
    public function get_direct_parents($skill_id)
734
    {
735
        $skill_rel_skill = new SkillRelSkill();
736
        $skills = $skill_rel_skill->get_direct_parents($skill_id, true);
737
        foreach($skills as &$skill) {
738
            $skill['data'] = self::get($skill['skill_id']);
739
            $skill_info2 = $skill_rel_skill->get_skill_info($skill['skill_id']);
740
            $skill['data']['parent_id'] = $skill_info2['parent_id'];
741
        }
742
        return $skills;
743
    }
744
745
    /**
746
     * Adds a new skill
747
     * @param array $params
748
     * @return bool|null
749
     */
750
    public function add($params)
751
    {
752
        if (!isset($params['parent_id'])) {
753
            $params['parent_id'] = 1;
754
        }
755
756 View Code Duplication
        if (!is_array($params['parent_id'])) {
757
            $params['parent_id'] = array($params['parent_id']);
758
        }
759
760
        $skill_rel_skill     = new SkillRelSkill();
761
        $skill_rel_gradebook = new SkillRelGradebook();
762
763
        //Saving name, description
764
765
        $skill_id = $this->save($params);
766
        if ($skill_id) {
767
            //Saving skill_rel_skill (parent_id, relation_type)
768
769 View Code Duplication
            foreach ($params['parent_id'] as $parent_id) {
0 ignored issues
show
Bug introduced by
The expression $params['parent_id'] 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...
770
                $relation_exists = $skill_rel_skill->relation_exists($skill_id, $parent_id);
771
                if (!$relation_exists) {
772
                    $attributes = array(
773
                        'skill_id'      => $skill_id,
774
                        'parent_id'     => $parent_id,
775
                        'relation_type' => (isset($params['relation_type'])?$params['relation_type']:0),
776
                        //'level'         => $params['level'],
777
                    );
778
                    $skill_rel_skill->save($attributes);
779
                }
780
            }
781
782
            if (!empty($params['gradebook_id'])) {
783
                foreach ($params['gradebook_id'] as $gradebook_id) {
784
                    $attributes = array();
785
                    $attributes['gradebook_id'] = $gradebook_id;
786
                    $attributes['skill_id']     = $skill_id;
787
                    $skill_rel_gradebook->save($attributes);
788
                }
789
            }
790
            return $skill_id;
791
        }
792
        return null;
793
    }
794
795
    /**
796
     * @param int $user_id
797
     * @param int $gradebook_id
798
     * @param int $courseId
799
     * @param int $sessionId
800
     */
801
    public function add_skill_to_user($user_id, $gradebook_id, $courseId = 0, $sessionId = 0)
802
    {
803
        $skill_gradebook = new SkillRelGradebook();
804
        $skill_rel_user  = new SkillRelUser();
805
806
        $skill_gradebooks = $skill_gradebook->get_all(array('where' => array('gradebook_id = ?' => $gradebook_id)));
807
        if (!empty($skill_gradebooks)) {
808
            foreach ($skill_gradebooks as $skill_gradebook) {
809
                $user_has_skill = $this->user_has_skill($user_id, $skill_gradebook['skill_id'], $courseId, $sessionId);
810
                if (!$user_has_skill) {
811
                    $params = array(
812
                        'user_id' => $user_id,
813
                        'skill_id' => $skill_gradebook['skill_id'],
814
                        'acquired_skill_at' => api_get_utc_datetime(),
815
                        'course_id' => intval($courseId),
816
                        'session_id' => $sessionId ? intval($sessionId) : null
817
                    );
818
819
                    $skill_rel_user->save($params);
820
                }
821
            }
822
        }
823
    }
824
825
    /* Deletes a skill */
826
    public function delete($skill_id)
827
    {
828
        /*$params = array('skill_id' => $skill_id);
829
830
        $skill_rel_skill     = new SkillRelSkill();
831
        $skills = $skill_rel_skill->get_all(array('where'=>array('skill_id = ?' =>$skill_id)));
832
833
        $skill_rel_profile     = new SkillRelProfile();
834
        $skill_rel_gradebook = new SkillRelGradebook();
835
        $skill_rel_user     = new SkillRelUser();
836
837
        $this->delete($skill_id);
838
839
        $skill_rel_gradebook->delete($params);*/
840
    }
841
842
    /**
843
     * @param array $params
844
     * @return null
845
     */
846
    public function edit($params)
847
    {
848
        if (!isset($params['parent_id'])) {
849
            $params['parent_id'] = 1;
850
        }
851
        $skill_rel_skill     = new SkillRelSkill();
852
        $skill_rel_gradebook = new SkillRelGradebook();
853
854
        //Saving name, description
855
        $this->update($params);
856
857
        $skill_id = $params['id'];
858
859
        if ($skill_id) {
860
            //Saving skill_rel_skill (parent_id, relation_type)
861
862 View Code Duplication
            if (!is_array($params['parent_id'])) {
863
                $params['parent_id'] = array($params['parent_id']);
864
            }
865
866 View Code Duplication
            foreach ($params['parent_id'] as $parent_id) {
867
                $relation_exists = $skill_rel_skill->relation_exists($skill_id, $parent_id);
868
                if (!$relation_exists) {
869
                    $attributes = array(
870
                        'skill_id'      => $skill_id,
871
                        'parent_id'     => $parent_id,
872
                        'relation_type' => $params['relation_type'],
873
                        //'level'         => $params['level'],
874
                    );
875
                    $skill_rel_skill->update_by_skill($attributes);
876
                }
877
            }
878
879
            $skill_rel_gradebook->update_gradebooks_by_skill($skill_id, $params['gradebook_id']);
880
            return $skill_id;
881
        }
882
        return null;
883
    }
884
885
    /**
886
     * Get user's skills
887
     *
888
     * @param int $userId User's id
0 ignored issues
show
Bug introduced by
There is no parameter named $userId. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
889
     * @param bool $get_skill_data
890
     */
891
    public function get_user_skills($user_id, $get_skill_data = false)
892
    {
893
        $user_id = intval($user_id);
894
        $sql = 'SELECT DISTINCT s.id, s.name, s.icon, u.id as issue
895
                FROM '.$this->table_skill_rel_user.' u
896
                INNER JOIN '.$this->table.' s
897
                ON u.skill_id = s.id
898
                WHERE user_id = '.$user_id;
899
900
        $result = Database::query($sql);
901
        $skills = Database::store_result($result, 'ASSOC');
902
        $uploadPath = api_get_path(WEB_UPLOAD_PATH);
903
        $clean_skill = array();
904
        if (!empty($skills)) {
905
            foreach ($skills as $skill) {
906
                if ($get_skill_data) {
907
                    $iconThumb = null;
908
                    $iconPath = null;
909
910
                    if (!empty($skill['icon'])) {
911
                        $iconThumb = sprintf(
912
                            "badges/%s-small.png",
913
                            sha1($skill['name'])
914
                        );
915
916
                        $iconPath = sprintf(
917
                            "badges/%s.png",
918
                            sha1($skill['name'])
919
                        );
920
                    }
921
                    $clean_skill[$skill['id']] = array_merge(
922
                        $skill,
923
                        array(
924
                            'web_icon_thumb_path' => $uploadPath.$iconThumb,
925
                            'web_icon_path' => $uploadPath.$iconPath
926
                        )
927
                    );
928
                } else {
929
                    $clean_skill[$skill['id']] = $skill['id'];
930
                }
931
            }
932
        }
933
934
        return $clean_skill;
935
    }
936
937
    /**
938
     * @param int $user_id
939
     * @param int $skill_id
940
     * @param bool $return_flat_array
941
     * @param bool $add_root
942
     * @return array|null
943
     */
944
    public function get_skills_tree($user_id = null, $skill_id = null, $return_flat_array = false, $add_root = false)
945
    {
946
        if ($skill_id == 1) {
947
            $skill_id = 0;
948
        }
949
        if (isset($user_id) && !empty($user_id)) {
950
            $skills = $this->get_all(true, $user_id, null, $skill_id);
951
        } else {
952
            $skills = $this->get_all(false, false, null, $skill_id);
953
        }
954
955
        $original_skill = $this->list = $skills;
956
957
        // Show 1 item
958
        if (!empty($skill_id)) {
959
            if ($add_root) {
960
                if (!empty($skill_id)) {
961
                    // Default root node
962
                    $skills[1] = array(
963
                        'id' => '1',
964
                        'name' => get_lang('Root'),
965
                        'parent_id' => '0'
966
                    );
967
                    $skill_info = $this->get_skill_info($skill_id);
968
969
                    // 2nd node
970
                    $skills[$skill_id] = $skill_info;
971
                    // Uncomment code below to hide the searched skill
972
                    $skills[$skill_id]['data']['parent_id'] =  $skill_info['extra']['parent_id'];
973
                    $skills[$skill_id]['parent_id'] =  1;
974
                }
975
            }
976
        }
977
978
        $refs = array();
979
        $skills_tree = null;
980
981
        // Create references for all nodes
982
        $flat_array = array();
983
        $family = array();
984
        if (!empty($skills)) {
985
            foreach ($skills as &$skill) {
986
                if ($skill['parent_id'] == 0) {
987
                    $skill['parent_id'] = 'root';
988
                }
989
990
                // because except main keys (id, name, children) others keys
991
                // are not saved while in the space tree
992
                $skill['data'] = array('parent_id' => $skill['parent_id']);
993
994
                // If a short code was defined, send the short code to replace
995
                // skill name (to shorten the text in the wheel)
996
                if (
997
                    !empty($skill['short_code']) &&
998
                    api_get_setting('show_full_skill_name_on_skill_wheel') === 'false'
999
                ) {
1000
                    $skill['data']['short_code'] = $skill['short_code'];
1001
                }
1002
1003
                $skill['data']['name'] = $skill['name'];
1004
1005
                // In order to paint all members of a family with the same color
1006
                if (empty($skill_id)) {
1007 View Code Duplication
                    if ($skill['parent_id'] == 1) {
1008
                        $family[$skill['id']] = $this->get_all_children($skill['id']);
1009
                    }
1010 View Code Duplication
                } else {
1011
                    if ($skill['parent_id'] == $skill_id) {
1012
                        $family[$skill['id']] = $this->get_all_children($skill['id']);
1013
                    }
1014
1015
                    /*if ($skill_id == $skill['id']) {
1016
                        $skill['parent_id'] = 1;
1017
                    }*/
1018
                }
1019
1020
                if (!isset($skill['data']['real_parent_id'])) {
1021
                    $skill['data']['real_parent_id'] = $skill['parent_id'];
1022
                }
1023
1024
                // User achieved the skill (depends in the gradebook with certification)
1025
                $skill['data']['achieved'] = false;
1026
                if ($user_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $user_id of type null|integer is loosely compared to true; 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...
1027
                    $skill['data']['achieved'] = $this->user_has_skill($user_id, $skill['id']);
1028
                }
1029
1030
                // Check if the skill has related gradebooks
1031
                $skill['data']['skill_has_gradebook'] = false;
1032
                if (isset($skill['gradebooks']) && !empty($skill['gradebooks'])) {
1033
                    $skill['data']['skill_has_gradebook'] = true;
1034
                }
1035
                $refs[$skill['id']] = &$skill;
1036
                $flat_array[$skill['id']] =  &$skill;
1037
            }
1038
1039
            // Checking family value
1040
1041
            $family_id = 1;
1042
            $new_family_array = array();
1043
            foreach ($family as $main_family_id => $family_items) {
1044
                if (!empty($family_items)) {
1045
                    foreach ($family_items as $item) {
1046
                        $new_family_array[$item['skill_id']] = $family_id;
1047
                    }
1048
                }
1049
                $new_family_array[$main_family_id] = $family_id;
1050
                $family_id++;
1051
            }
1052
1053
            if (empty($original_skill)) {
1054
                $refs['root']['children'][0] = $skills[1];
1055
                $skills[$skill_id]['data']['family_id'] = 1;
1056
                $refs['root']['children'][0]['children'][0] = $skills[$skill_id];
1057
                $flat_array[$skill_id] =  $skills[$skill_id];
1058
            } else {
1059
                // Moving node to the children index of their parents
1060
1061
                foreach ($skills as $my_skill_id => &$skill) {
1062
                    if (isset($new_family_array[$skill['id']])) {
1063
                        $skill['data']['family_id'] = $new_family_array[$skill['id']];
1064
                    }
1065
                    $refs[$skill['parent_id']]['children'][] = &$skill;
1066
                    $flat_array[$my_skill_id] =  $skill;
1067
                }
1068
            }
1069
1070
            $skills_tree = array(
1071
                'name' => get_lang('SkillRootName'),
1072
                'id' => 'root',
1073
                'children' => $refs['root']['children'],
1074
                'data' => array()
1075
            );
1076
        }
1077
1078
        if ($return_flat_array) {
1079
            return $flat_array;
1080
        }
1081
        unset($skills);
1082
1083
        return $skills_tree;
1084
    }
1085
1086
    /**
1087
     * Get skills tree as a simplified JSON structure
1088
     * @param int user id
1089
     * @param int skill id
1090
     * @param bool return a flat array or not
1091
     * @param int depth of the skills
1092
     *
1093
     */
1094
    public function get_skills_tree_json($user_id = null, $skill_id = null, $return_flat_array = false, $main_depth = 2)
1095
    {
1096
        $tree = $this->get_skills_tree($user_id, $skill_id, $return_flat_array, true);
1097
        $simple_tree = array();
1098
        if (!empty($tree['children'])) {
1099
            foreach ($tree['children'] as $element) {
1100
                $simple_tree[] = array(
1101
                    'name' => $element['name'],
1102
                    'children' => $this->get_skill_json($element['children'], 1, $main_depth)
1103
                );
1104
            }
1105
        }
1106
1107
        return json_encode($simple_tree[0]['children']);
1108
    }
1109
1110
    /**
1111
     * Get JSON element
1112
     * @param array $subtree
1113
     * @param int $depth
1114
     * @param int $max_depth
1115
     * @return array|null
1116
     */
1117
    public function get_skill_json($subtree, $depth = 1, $max_depth = 2)
1118
    {
1119
        $simple_sub_tree = array();
1120
        if (is_array($subtree)) {
1121
            $counter = 1;
1122
            foreach ($subtree as $elem) {
1123
                $tmp = array();
1124
                $tmp['name'] = $elem['name'];
1125
                $tmp['id'] = $elem['id'];
1126
                $tmp['isSearched'] = self::isSearched($elem['id']);
1127
1128
                if (isset($elem['children']) && is_array($elem['children'])) {
1129
                    $tmp['children'] = $this->get_skill_json($elem['children'], $depth + 1, $max_depth);
1130
                } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches 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 else branches can be removed.

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

could be turned into

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

This is much more concise to read.

Loading history...
1131
                    //$tmp['colour'] = $this->colours[$depth][rand(0,3)];
1132
                }
1133
                if ($depth > $max_depth) {
1134
                    continue;
1135
                }
1136
1137
                $tmp['depth'] = $depth;
1138
                $tmp['counter'] = $counter;
1139
                $counter++;
1140
1141 View Code Duplication
                if (isset($elem['data']) && is_array($elem['data'])) {
1142
                    foreach ($elem['data'] as $key => $item) {
1143
                        $tmp[$key] = $item;
1144
                    }
1145
                }
1146
                $simple_sub_tree[] = $tmp;
1147
            }
1148
            return $simple_sub_tree;
1149
        }
1150
        return null;
1151
    }
1152
1153
    /**
1154
     * @param int $user_id
1155
     * @return bool
1156
     */
1157 View Code Duplication
    public function get_user_skill_ranking($user_id)
1158
    {
1159
        $user_id = intval($user_id);
1160
        $sql = "SELECT count(skill_id) count FROM {$this->table} s
1161
                INNER JOIN {$this->table_skill_rel_user} su
1162
                ON (s.id = su.skill_id)
1163
                WHERE user_id = $user_id";
1164
        $result  = Database::query($sql);
1165
        if (Database::num_rows($result)) {
1166
            $result = Database::fetch_row($result);
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, fetch_row() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1167
            return $result[0];
1168
        }
1169
        return false;
1170
    }
1171
1172
    /**
1173
     * @param $start
1174
     * @param $limit
1175
     * @param $sidx
1176
     * @param $sord
1177
     * @param $where_condition
1178
     * @return array
1179
     */
1180
    public function get_user_list_skill_ranking($start, $limit, $sidx, $sord, $where_condition)
1181
    {
1182
        $start = intval($start);
1183
        $limit = intval($limit);
1184
        /*  ORDER BY $sidx $sord */
1185
        $sql = "SELECT *, @rownum:=@rownum+1 rank FROM (
1186
                    SELECT u.user_id, firstname, lastname, count(username) skills_acquired
1187
                    FROM {$this->table} s INNER JOIN {$this->table_skill_rel_user} su ON (s.id = su.skill_id)
1188
                    INNER JOIN {$this->table_user} u ON u.user_id = su.user_id, (SELECT @rownum:=0) r
1189
                    WHERE 1=1 $where_condition
1190
                    GROUP BY username
1191
                    ORDER BY skills_acquired desc
1192
                    LIMIT $start , $limit)  AS T1, (SELECT @rownum:=0) r";
1193
        $result = Database::query($sql);
1194
        if (Database::num_rows($result)) {
1195
            return Database::store_result($result, 'ASSOC');
1196
        }
1197
1198
        return array();
1199
    }
1200
1201
    /**
1202
     * @return int
1203
     */
1204 View Code Duplication
    public function get_user_list_skill_ranking_count()
1205
    {
1206
        $sql    = "SELECT count(*) FROM (
1207
                        SELECT count(distinct 1)
1208
                        FROM {$this->table} s
1209
                        INNER JOIN {$this->table_skill_rel_user} su
1210
                        ON (s.id = su.skill_id)
1211
                        INNER JOIN {$this->table_user} u
1212
                        ON u.user_id = su.user_id
1213
                        GROUP BY username
1214
                     ) as T1";
1215
        $result = Database::query($sql);
1216
        if (Database::num_rows($result)) {
1217
            $result = Database::fetch_row($result);
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, fetch_row() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1218
1219
            return $result[0];
1220
        }
1221
        return 0;
1222
    }
1223
1224
    /**
1225
     * @param string $course_code
1226
     * @return int
1227
     */
1228 View Code Duplication
    public function get_count_skills_by_course($course_code)
1229
    {
1230
        $sql = "SELECT count(skill_id) as count
1231
                FROM {$this->table_gradebook} g
1232
                INNER JOIN {$this->table_skill_rel_gradebook} sg
1233
                ON g.id = sg.gradebook_id
1234
                WHERE course_code = '$course_code'";
1235
1236
        $result = Database::query($sql);
1237
        if (Database::num_rows($result)) {
1238
            $result = Database::fetch_row($result);
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, fetch_row() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1239
            return $result[0];
1240
        }
1241
        return 0;
1242
    }
1243
1244
    /**
1245
     * @param int $skill_id
1246
     * @return array
1247
     */
1248 View Code Duplication
    public function get_courses_by_skill($skill_id)
1249
    {
1250
        $skill_id = intval($skill_id);
1251
        $sql = "SELECT c.title, c.code
1252
                FROM {$this->table_gradebook} g
1253
                INNER JOIN {$this->table_skill_rel_gradebook} sg
1254
                ON g.id = sg.gradebook_id
1255
                INNER JOIN {$this->table_course} c
1256
                ON c.code = g.course_code
1257
                WHERE sg.skill_id = $skill_id
1258
                AND (g.session_id IS NULL OR g.session_id = 0)";
1259
        $result   = Database::query($sql);
1260
1261
        return Database::store_result($result, 'ASSOC');
1262
    }
1263
1264
    /**
1265
     * Check if the user has the skill
1266
     * @param int $userId The user id
1267
     * @param int $skillId The skill id
1268
     * @param int $courseId Optional. The course id
1269
     * @param int $sessionId Optional. The session id
1270
     * @return boolean Whether the user has the skill return true. Otherwise return false
1271
     */
1272
    public function user_has_skill($userId, $skillId, $courseId = 0, $sessionId = 0)
1273
    {
1274
        $courseId = intval($courseId);
1275
        $sessionId = intval($sessionId);
1276
1277
        $whereConditions = array(
1278
            'user_id = ? ' => intval($userId),
1279
            'AND skill_id = ? ' => intval($skillId)
1280
        );
1281
1282
        if ($courseId > 0) {
1283
            $whereConditions['AND course_id = ? '] = $courseId;
1284
            $whereConditions['AND session_id = ? '] = $sessionId ? $sessionId : null;
1285
        }
1286
1287
        $result = Database::select(
1288
            'COUNT(1) AS qty',
1289
            $this->table_skill_rel_user, array(
1290
                'where' => $whereConditions
1291
            ),
1292
            'first'
1293
        );
1294
1295
        if ($result != false) {
1296
            if ($result['qty'] > 0) {
1297
                return true;
1298
            }
1299
        }
1300
1301
        return false;
1302
    }
1303
1304
    /**
1305
     * Check if a skill is searched
1306
     * @param int $id The skill id
1307
     * @return boolean Whether el skill is searched return true. Otherwise return false
1308
     */
1309
    public static function isSearched($id)
1310
    {
1311
        $id = intval($id);
1312
1313
        if (empty($id)) {
1314
            return false;
1315
        }
1316
1317
        $skillRelProfileTable = Database::get_main_table(TABLE_MAIN_SKILL_REL_PROFILE);
1318
1319
        $result = Database::select(
1320
            'COUNT( DISTINCT `skill_id`) AS qty',
1321
            $skillRelProfileTable,
1322
            array(
1323
                'where' => array(
1324
                    'skill_id = ?' => $id
1325
                )
1326
            ),
1327
            'first'
1328
        );
1329
1330
        if ($result === false) {
1331
            return false;
1332
        }
1333
1334
        if ($result['qty'] > 0) {
1335
            return true;
1336
        }
1337
1338
        return false;
1339
    }
1340
1341
    /**
1342
     * Get the achieved skills by course
1343
     * @param int $courseId The course id
1344
     * @return array The skills list
1345
     */
1346 View Code Duplication
    public function listAchievedByCourse($courseId)
1347
    {
1348
        $courseId = intval($courseId);
1349
1350
        if ($courseId == 0) {
1351
            return array();
1352
        }
1353
1354
        $list = array();
1355
1356
        $sql = "SELECT
1357
                    course.id c_id,
1358
                    course.title c_name,
1359
                    course.directory c_directory,
1360
                    user.user_id,
1361
                    user.lastname,
1362
                    user.firstname,
1363
                    user.username,
1364
                    skill.id skill_id,
1365
                    skill.name skill_name,
1366
                    sru.acquired_skill_at
1367
                FROM {$this->table_skill_rel_user} AS sru
1368
                INNER JOIN {$this->table_course}
1369
                ON sru.course_id = course.id
1370
                INNER JOIN {$this->table_user}
1371
                ON sru.user_id = user.user_id
1372
                INNER JOIN {$this->table}
1373
                ON sru.skill_id = skill.id
1374
                WHERE course.id = $courseId";
1375
1376
        $result = Database::query($sql);
1377
1378
        while ($row = Database::fetch_assoc($result)) {
1379
            $list[] = $row;
1380
        }
1381
1382
        return $list;
1383
    }
1384
1385
    /**
1386
     * Get the users list who achieved a skill
1387
     * @param int $skillId The skill id
1388
     *
1389
     * @return array The users list
1390
     */
1391 View Code Duplication
    public function listUsersWhoAchieved($skillId)
1392
    {
1393
        $skillId = intval($skillId);
1394
1395
        if ($skillId == 0) {
1396
            return array();
1397
        }
1398
1399
        $list = array();
1400
1401
        $sql = "SELECT
1402
                    course.id c_id,
1403
                    course.title c_name,
1404
                    course.directory c_directory,
1405
                    user.user_id,
1406
                    user.lastname,
1407
                    user.firstname,
1408
                    user.username,
1409
                    skill.id skill_id,
1410
                    skill.name skill_name,
1411
                    sru.acquired_skill_at
1412
                FROM {$this->table_skill_rel_user} AS sru
1413
                INNER JOIN {$this->table_course}
1414
                ON sru.course_id = course.id
1415
                INNER JOIN {$this->table_user}
1416
                ON sru.user_id = user.user_id
1417
                INNER JOIN {$this->table}
1418
                ON sru.skill_id = skill.id
1419
                WHERE skill.id = $skillId ";
1420
1421
        $result = Database::query($sql);
1422
1423
        while ($row = Database::fetch_assoc($result)) {
1424
            $list[] = $row;
1425
        }
1426
1427
        return $list;
1428
    }
1429
1430
    /**
1431
     * Get the session list where the user can achieve a skill
1432
     * @param int $skillId The skill id
1433
     * @return array
1434
     */
1435 View Code Duplication
    public function getSessionsBySkill($skillId)
1436
    {
1437
        $skillId = intval($skillId);
1438
1439
        $sql = "SELECT s.id, s.name
1440
                FROM {$this->table_gradebook} g
1441
                INNER JOIN {$this->table_skill_rel_gradebook} sg ON g.id = sg.gradebook_id
1442
                INNER JOIN {$this->sessionTable} s ON g.session_id = s.id
1443
                WHERE sg.skill_id = $skillId
1444
                AND g.session_id > 0";
1445
1446
        $result   = Database::query($sql);
1447
1448
        return Database::store_result($result, 'ASSOC');
1449
    }
1450
1451
    /**
1452
     * Check if the $fromUser can comment the $toUser skill issue
1453
     * @param Chamilo\UserBundle\Entity\User $fromUser
1454
     * @param Chamilo\UserBundle\Entity\User $toUser
1455
     * @return boolean
1456
     */
1457
    public static function userCanAddFeedbackToUser($fromUser, $toUser)
1458
    {
1459
        if (api_is_platform_admin()) {
1460
            return true;
1461
        }
1462
1463
        $entityManager = Database::getManager();
1464
        $userRepo = $entityManager->getRepository('ChamiloUserBundle:User');
1465
        $fromUserStatus = $fromUser->getStatus();
1466
1467
        switch ($fromUserStatus) {
1468
            case SESSIONADMIN:
1469
                if (api_get_setting('allow_session_admins_to_manage_all_sessions') === 'true') {
1470
                    if ($toUser->getCreatorId() === $fromUser->getId()) {
1471
                        return true;
1472
                    }
1473
                }
1474
1475
                $sessionAdmins = $userRepo->getSessionAdmins($toUser);
1476
1477
                foreach ($sessionAdmins as $sessionAdmin) {
1478
                    if ($sessionAdmin->getId() !== $fromUser->getId()) {
1479
                        continue;
1480
                    }
1481
1482
                    return true;
1483
                }
1484
                break;
1485
            case STUDENT_BOSS:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1486
                $studentBosses = $userRepo->getStudentBosses($toUser);
1487
1488
                foreach ($studentBosses as $studentBoss) {
1489
                    if ($studentBoss->getId() !== $fromUser->getId()) {
1490
                        continue;
1491
                    }
1492
1493
                    return true;
1494
                }
1495
            case DRH:
1496
                return UserManager::is_user_followed_by_drh($toUser->getId(), $fromUser->getId());
1497
        }
1498
1499
        return false;
1500
    }
1501
1502
}
1503