Completed
Push — 1.11.x ( 747e79...744431 )
by José
148:16 queued 112:20
created

Skill::get_skill_json()   C

Complexity

Conditions 11
Paths 3

Size

Total Lines 41
Code Lines 26

Duplication

Lines 5
Ratio 12.2 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 11
eloc 26
c 1
b 1
f 0
nc 3
nop 4
dl 5
loc 41
rs 5.2653

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
     * @param bool filter status
1093
     * @return json
1094
     */
1095
    public function get_skills_tree_json($user_id = null, $skill_id = null, $return_flat_array = false, $main_depth = 2, $filter_status = false)
1096
    {
1097
        $tree = $this->get_skills_tree($user_id, $skill_id, $return_flat_array, true);
1098
        $simple_tree = array();
1099
        if (!empty($tree['children'])) {
1100
            foreach ($tree['children'] as $element) {
1101
                if ($filter_status) {
1102
                    if (intval($element['status'])) {
1103
                        $simple_tree[] = array(
1104
                            'name' => $element['name'],
1105
                            'children' => $this->get_skill_json($element['children'], 1, $main_depth, $filter_status)
1106
                        );
1107
                    }
1108
                } else {
1109
                    $simple_tree[] = array(
1110
                        'name' => $element['name'],
1111
                        'children' => $this->get_skill_json($element['children'], 1, $main_depth)
1112
                    );
1113
                }
1114
            }
1115
        }
1116
1117
        return json_encode($simple_tree[0]['children']);
1118
    }
1119
1120
    /**
1121
     * Get JSON element
1122
     * @param array $subtree
1123
     * @param int $depth
1124
     * @param int $max_depth
1125
     * @param bool $filter_status
1126
     * @return array|null
1127
     */
1128
    public function get_skill_json($subtree, $depth = 1, $max_depth = 2, $filter_status = false)
1129
    {
1130
        $simple_sub_tree = array();
1131
        if (is_array($subtree)) {
1132
            $counter = 1;
1133
            foreach ($subtree as $elem) {
1134
                if ($filter_status) {
1135
                    if (!intval($elem['status'])) {
1136
                        break 1;
1137
                    }
1138
                }
1139
1140
                $tmp = array();
1141
                $tmp['name'] = $elem['name'];
1142
                $tmp['id'] = $elem['id'];
1143
                $tmp['isSearched'] = self::isSearched($elem['id']);
1144
1145
                if (isset($elem['children']) && is_array($elem['children'])) {
1146
                    $tmp['children'] = $this->get_skill_json($elem['children'], $depth + 1, $max_depth, $filter_status);
1147
                } 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...
1148
                    //$tmp['colour'] = $this->colours[$depth][rand(0,3)];
1149
                }
1150
                if ($depth > $max_depth) {
1151
                    continue;
1152
                }
1153
1154
                $tmp['depth'] = $depth;
1155
                $tmp['counter'] = $counter;
1156
                $counter++;
1157
1158 View Code Duplication
                if (isset($elem['data']) && is_array($elem['data'])) {
1159
                    foreach ($elem['data'] as $key => $item) {
1160
                        $tmp[$key] = $item;
1161
                    }
1162
                }
1163
                $simple_sub_tree[] = $tmp;
1164
            }
1165
            return $simple_sub_tree;
1166
        }
1167
        return null;
1168
    }
1169
1170
    /**
1171
     * @param int $user_id
1172
     * @return bool
1173
     */
1174 View Code Duplication
    public function get_user_skill_ranking($user_id)
1175
    {
1176
        $user_id = intval($user_id);
1177
        $sql = "SELECT count(skill_id) count FROM {$this->table} s
1178
                INNER JOIN {$this->table_skill_rel_user} su
1179
                ON (s.id = su.skill_id)
1180
                WHERE user_id = $user_id";
1181
        $result  = Database::query($sql);
1182
        if (Database::num_rows($result)) {
1183
            $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...
1184
            return $result[0];
1185
        }
1186
        return false;
1187
    }
1188
1189
    /**
1190
     * @param $start
1191
     * @param $limit
1192
     * @param $sidx
1193
     * @param $sord
1194
     * @param $where_condition
1195
     * @return array
1196
     */
1197
    public function get_user_list_skill_ranking($start, $limit, $sidx, $sord, $where_condition)
1198
    {
1199
        $start = intval($start);
1200
        $limit = intval($limit);
1201
        /*  ORDER BY $sidx $sord */
1202
        $sql = "SELECT *, @rownum:=@rownum+1 rank FROM (
1203
                    SELECT u.user_id, firstname, lastname, count(username) skills_acquired
1204
                    FROM {$this->table} s INNER JOIN {$this->table_skill_rel_user} su ON (s.id = su.skill_id)
1205
                    INNER JOIN {$this->table_user} u ON u.user_id = su.user_id, (SELECT @rownum:=0) r
1206
                    WHERE 1=1 $where_condition
1207
                    GROUP BY username
1208
                    ORDER BY skills_acquired desc
1209
                    LIMIT $start , $limit)  AS T1, (SELECT @rownum:=0) r";
1210
        $result = Database::query($sql);
1211
        if (Database::num_rows($result)) {
1212
            return Database::store_result($result, 'ASSOC');
1213
        }
1214
1215
        return array();
1216
    }
1217
1218
    /**
1219
     * @return int
1220
     */
1221 View Code Duplication
    public function get_user_list_skill_ranking_count()
1222
    {
1223
        $sql    = "SELECT count(*) FROM (
1224
                        SELECT count(distinct 1)
1225
                        FROM {$this->table} s
1226
                        INNER JOIN {$this->table_skill_rel_user} su
1227
                        ON (s.id = su.skill_id)
1228
                        INNER JOIN {$this->table_user} u
1229
                        ON u.user_id = su.user_id
1230
                        GROUP BY username
1231
                     ) as T1";
1232
        $result = Database::query($sql);
1233
        if (Database::num_rows($result)) {
1234
            $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...
1235
1236
            return $result[0];
1237
        }
1238
        return 0;
1239
    }
1240
1241
    /**
1242
     * @param string $course_code
1243
     * @return int
1244
     */
1245 View Code Duplication
    public function get_count_skills_by_course($course_code)
1246
    {
1247
        $sql = "SELECT count(skill_id) as count
1248
                FROM {$this->table_gradebook} g
1249
                INNER JOIN {$this->table_skill_rel_gradebook} sg
1250
                ON g.id = sg.gradebook_id
1251
                WHERE course_code = '$course_code'";
1252
1253
        $result = Database::query($sql);
1254
        if (Database::num_rows($result)) {
1255
            $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...
1256
            return $result[0];
1257
        }
1258
        return 0;
1259
    }
1260
1261
    /**
1262
     * @param int $skill_id
1263
     * @return array
1264
     */
1265 View Code Duplication
    public function get_courses_by_skill($skill_id)
1266
    {
1267
        $skill_id = intval($skill_id);
1268
        $sql = "SELECT c.title, c.code
1269
                FROM {$this->table_gradebook} g
1270
                INNER JOIN {$this->table_skill_rel_gradebook} sg
1271
                ON g.id = sg.gradebook_id
1272
                INNER JOIN {$this->table_course} c
1273
                ON c.code = g.course_code
1274
                WHERE sg.skill_id = $skill_id
1275
                AND (g.session_id IS NULL OR g.session_id = 0)";
1276
        $result   = Database::query($sql);
1277
1278
        return Database::store_result($result, 'ASSOC');
1279
    }
1280
1281
    /**
1282
     * Check if the user has the skill
1283
     * @param int $userId The user id
1284
     * @param int $skillId The skill id
1285
     * @param int $courseId Optional. The course id
1286
     * @param int $sessionId Optional. The session id
1287
     * @return boolean Whether the user has the skill return true. Otherwise return false
1288
     */
1289
    public function user_has_skill($userId, $skillId, $courseId = 0, $sessionId = 0)
1290
    {
1291
        $courseId = intval($courseId);
1292
        $sessionId = intval($sessionId);
1293
1294
        $whereConditions = array(
1295
            'user_id = ? ' => intval($userId),
1296
            'AND skill_id = ? ' => intval($skillId)
1297
        );
1298
1299
        if ($courseId > 0) {
1300
            $whereConditions['AND course_id = ? '] = $courseId;
1301
            $whereConditions['AND session_id = ? '] = $sessionId ? $sessionId : null;
1302
        }
1303
1304
        $result = Database::select(
1305
            'COUNT(1) AS qty',
1306
            $this->table_skill_rel_user, array(
1307
                'where' => $whereConditions
1308
            ),
1309
            'first'
1310
        );
1311
1312
        if ($result != false) {
1313
            if ($result['qty'] > 0) {
1314
                return true;
1315
            }
1316
        }
1317
1318
        return false;
1319
    }
1320
1321
    /**
1322
     * Check if a skill is searched
1323
     * @param int $id The skill id
1324
     * @return boolean Whether el skill is searched return true. Otherwise return false
1325
     */
1326
    public static function isSearched($id)
1327
    {
1328
        $id = intval($id);
1329
1330
        if (empty($id)) {
1331
            return false;
1332
        }
1333
1334
        $skillRelProfileTable = Database::get_main_table(TABLE_MAIN_SKILL_REL_PROFILE);
1335
1336
        $result = Database::select(
1337
            'COUNT( DISTINCT `skill_id`) AS qty',
1338
            $skillRelProfileTable,
1339
            array(
1340
                'where' => array(
1341
                    'skill_id = ?' => $id
1342
                )
1343
            ),
1344
            'first'
1345
        );
1346
1347
        if ($result === false) {
1348
            return false;
1349
        }
1350
1351
        if ($result['qty'] > 0) {
1352
            return true;
1353
        }
1354
1355
        return false;
1356
    }
1357
1358
    /**
1359
     * Get the achieved skills by course
1360
     * @param int $courseId The course id
1361
     * @return array The skills list
1362
     */
1363 View Code Duplication
    public function listAchievedByCourse($courseId)
1364
    {
1365
        $courseId = intval($courseId);
1366
1367
        if ($courseId == 0) {
1368
            return array();
1369
        }
1370
1371
        $list = array();
1372
1373
        $sql = "SELECT
1374
                    course.id c_id,
1375
                    course.title c_name,
1376
                    course.directory c_directory,
1377
                    user.user_id,
1378
                    user.lastname,
1379
                    user.firstname,
1380
                    user.username,
1381
                    skill.id skill_id,
1382
                    skill.name skill_name,
1383
                    sru.acquired_skill_at
1384
                FROM {$this->table_skill_rel_user} AS sru
1385
                INNER JOIN {$this->table_course}
1386
                ON sru.course_id = course.id
1387
                INNER JOIN {$this->table_user}
1388
                ON sru.user_id = user.user_id
1389
                INNER JOIN {$this->table}
1390
                ON sru.skill_id = skill.id
1391
                WHERE course.id = $courseId";
1392
1393
        $result = Database::query($sql);
1394
1395
        while ($row = Database::fetch_assoc($result)) {
1396
            $list[] = $row;
1397
        }
1398
1399
        return $list;
1400
    }
1401
1402
    /**
1403
     * Get the users list who achieved a skill
1404
     * @param int $skillId The skill id
1405
     *
1406
     * @return array The users list
1407
     */
1408 View Code Duplication
    public function listUsersWhoAchieved($skillId)
1409
    {
1410
        $skillId = intval($skillId);
1411
1412
        if ($skillId == 0) {
1413
            return array();
1414
        }
1415
1416
        $list = array();
1417
1418
        $sql = "SELECT
1419
                    course.id c_id,
1420
                    course.title c_name,
1421
                    course.directory c_directory,
1422
                    user.user_id,
1423
                    user.lastname,
1424
                    user.firstname,
1425
                    user.username,
1426
                    skill.id skill_id,
1427
                    skill.name skill_name,
1428
                    sru.acquired_skill_at
1429
                FROM {$this->table_skill_rel_user} AS sru
1430
                INNER JOIN {$this->table_course}
1431
                ON sru.course_id = course.id
1432
                INNER JOIN {$this->table_user}
1433
                ON sru.user_id = user.user_id
1434
                INNER JOIN {$this->table}
1435
                ON sru.skill_id = skill.id
1436
                WHERE skill.id = $skillId ";
1437
1438
        $result = Database::query($sql);
1439
1440
        while ($row = Database::fetch_assoc($result)) {
1441
            $list[] = $row;
1442
        }
1443
1444
        return $list;
1445
    }
1446
1447
    /**
1448
     * Get the session list where the user can achieve a skill
1449
     * @param int $skillId The skill id
1450
     * @return array
1451
     */
1452 View Code Duplication
    public function getSessionsBySkill($skillId)
1453
    {
1454
        $skillId = intval($skillId);
1455
1456
        $sql = "SELECT s.id, s.name
1457
                FROM {$this->table_gradebook} g
1458
                INNER JOIN {$this->table_skill_rel_gradebook} sg ON g.id = sg.gradebook_id
1459
                INNER JOIN {$this->sessionTable} s ON g.session_id = s.id
1460
                WHERE sg.skill_id = $skillId
1461
                AND g.session_id > 0";
1462
1463
        $result   = Database::query($sql);
1464
1465
        return Database::store_result($result, 'ASSOC');
1466
    }
1467
1468
    /**
1469
     * Check if the $fromUser can comment the $toUser skill issue
1470
     * @param Chamilo\UserBundle\Entity\User $fromUser
1471
     * @param Chamilo\UserBundle\Entity\User $toUser
1472
     * @return boolean
1473
     */
1474
    public static function userCanAddFeedbackToUser($fromUser, $toUser)
1475
    {
1476
        if (api_is_platform_admin()) {
1477
            return true;
1478
        }
1479
1480
        $entityManager = Database::getManager();
1481
        $userRepo = $entityManager->getRepository('ChamiloUserBundle:User');
1482
        $fromUserStatus = $fromUser->getStatus();
1483
1484
        switch ($fromUserStatus) {
1485
            case SESSIONADMIN:
1486
                if (api_get_setting('allow_session_admins_to_manage_all_sessions') === 'true') {
1487
                    if ($toUser->getCreatorId() === $fromUser->getId()) {
1488
                        return true;
1489
                    }
1490
                }
1491
1492
                $sessionAdmins = $userRepo->getSessionAdmins($toUser);
1493
1494
                foreach ($sessionAdmins as $sessionAdmin) {
1495
                    if ($sessionAdmin->getId() !== $fromUser->getId()) {
1496
                        continue;
1497
                    }
1498
1499
                    return true;
1500
                }
1501
                break;
1502
            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...
1503
                $studentBosses = $userRepo->getStudentBosses($toUser);
1504
1505
                foreach ($studentBosses as $studentBoss) {
1506
                    if ($studentBoss->getId() !== $fromUser->getId()) {
1507
                        continue;
1508
                    }
1509
1510
                    return true;
1511
                }
1512
            case DRH:
1513
                return UserManager::is_user_followed_by_drh($toUser->getId(), $fromUser->getId());
1514
        }
1515
1516
        return false;
1517
    }
1518
1519
}
1520