Passed
Push — 1.10.x ( 676aae...de380a )
by Yannick
64:26 queued 33:35
created

GradebookTable   F

Complexity

Total Complexity 159

Size/Duplication

Total Lines 1033
Duplicated Lines 4.36 %

Coupling/Cohesion

Components 1
Dependencies 14

Importance

Changes 0
Metric Value
wmc 159
lcom 1
cbo 14
dl 45
loc 1033
rs 1.7131
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
F __construct() 16 98 16
A get_data() 0 4 1
A get_total_number_of_items() 0 4 1
F get_table_data() 29 618 99
A getDataForGraph() 0 4 1
B getGraph() 0 85 6
A build_certificate_min_score() 0 4 1
A build_weight() 0 4 1
A build_course_code() 0 4 1
A build_id_column() 0 14 4
A build_type_column() 0 4 1
D build_name_link() 0 89 23
A build_edit_column() 0 14 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like GradebookTable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GradebookTable, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* For licensing terms, see license.txt */
3
4
use ChamiloSession as Session;
5
use CpChart\Chart\Cache as pCache;
6
use CpChart\Chart\Data as pData;
7
use CpChart\Chart\Image as pImage;
8
9
/**
10
 * GradebookTable Class
11
 * Table to display categories, evaluations and links
12
 * @author Stijn Konings
13
 * @author Bert Steppé (refactored, optimised)
14
 * @package chamilo.gradebook
15
 */
16
class GradebookTable extends SortableTable
17
{
18
    private $currentcat;
19
    private $datagen;
20
    private $evals_links;
21
    public $cats;
22
    private $dataForGraph;
23
    public $exportToPdf;
24
    public $teacherView;
25
    public $userId;
26
    public $studentList;
27
28
    /**
29
     * Constructor
30
     * @param Category $currentcat
31
     * @param array $cats
32
     * @param array $evals
33
     * @param array $links
34
     * @param null $addparams
35
     */
36
    public function __construct(
37
        $currentcat,
38
        $cats = array(),
39
        $evals = array(),
40
        $links = array(),
41
        $addparams = null,
42
        $exportToPdf = false,
43
        $showTeacherView = null,
44
        $userId = null,
45
        $studentList = array()
46
    ) {
47
        $this->teacherView = is_null($showTeacherView) ? api_is_allowed_to_edit(null, true) : $showTeacherView;
48
        $this->userId = is_null($userId) ? api_get_user_id() : $userId;
49
        $this->exportToPdf = $exportToPdf;
50
51
        parent::__construct(
52
            'gradebooklist',
53
            null,
54
            null,
55
            api_is_allowed_to_edit() ? 1 : 0,
56
            20,
57
            'ASC',
58
            'gradebook_list'
59
        );
60
61
        $this->evals_links = array_merge($evals, $links);
62
        $this->currentcat = $currentcat;
63
        $this->cats = $cats;
64
        $this->datagen = new GradebookDataGenerator($cats, $evals, $links);
65
66
        if (!empty($userId)) {
67
            $this->datagen->userId = $userId;
68
        }
69
70
        if (isset($addparams)) {
71
            $this->set_additional_parameters($addparams);
72
        }
73
74
        $column= 0;
75
        if ($this->teacherView) {
76
            if ($this->exportToPdf == false) {
77
                $this->set_header($column++, '', '', 'width="25px"');
78
            }
79
        }
80
81
        $this->set_header($column++, get_lang('Type'), '', 'width="35px"');
82
        $this->set_header($column++, get_lang('Name'), false);
83
84
        if ($this->exportToPdf == false) {
85
            $this->set_header($column++, get_lang('Description'), false);
86
        }
87
88
        if ($this->teacherView) {
89
            $this->set_header(
90
                $column++,
91
                get_lang('Weight'),
92
                '',
93
                'width="100px"'
94
            );
95
        } else {
96
            $this->set_header($column++, get_lang('Weight'), false);
97
            $this->set_header($column++, get_lang('Result'), false);
98
            $this->set_header($column++, get_lang('Ranking'), false);
99
            $this->set_header($column++, get_lang('BestScore'), false);
100
            $this->set_header($column++, get_lang('Average'), false);
101
102 View Code Duplication
            if (!empty($cats)) {
103
                if ($this->exportToPdf == false) {
104
                    $this->set_header($column++, get_lang('Actions'), false);
105
                }
106
            }
107
        }
108
109
        // Deactivates the odd/even alt rows in order that the +/- buttons work see #4047
110
        $this->odd_even_rows_enabled = false;
111
112
        // Admins get an edit column.
113
        if ($this->teacherView) {
114
            $this->set_header($column++, get_lang('Modify'), false, 'width="195px"');
115
            // Actions on multiple selected documents.
116
            $this->set_form_actions(array(
117
                    'setvisible' => get_lang('SetVisible'),
118
                    'setinvisible' => get_lang('SetInvisible'),
119
                    'deleted' => get_lang('DeleteSelected')
120
                )
121
            );
122 View Code Duplication
        } else {
123
            if (empty($_GET['selectcat']) && !$this->teacherView) {
124
                if ($this->exportToPdf == false) {
125
                    $this->set_header(
126
                        $column++,
127
                        get_lang('Certificates'),
128
                        false
129
                    );
130
                }
131
            }
132
        }
133
    }
134
135
    /**
136
     * @return GradebookDataGenerator
137
     */
138
    public function get_data()
139
    {
140
        return $this->datagen;
141
    }
142
143
    /**
144
     * Function used by SortableTable to get total number of items in the table
145
     * @return int
146
     */
147
    public function get_total_number_of_items()
148
    {
149
        return $this->datagen->get_total_items_count();
150
    }
151
152
    /**
153
     * Function used by SortableTable to generate the data to display
154
     * @param int $from
155
     * @param int $per_page
156
     * @param int $column
157
     * @param string $direction
158
     * @param int $sort
159
     * @return array|mixed
160
     */
161
    public function get_table_data($from = 1, $per_page = null, $column = null, $direction = null, $sort = null)
162
    {
163
        //variables load in index.php
164
        global $certificate_min_score;
165
        // determine sorting type
166
        $col_adjust = api_is_allowed_to_edit() ? 1 : 0;
167
        // By id
168
        $this->column = 5;
169
170
        switch ($this->column) {
171
            // Type
172
            case (0 + $col_adjust) :
173
                $sorting = GradebookDataGenerator :: GDG_SORT_TYPE;
174
                break;
175
            case (1 + $col_adjust) :
176
                $sorting = GradebookDataGenerator :: GDG_SORT_NAME;
177
                break;
178
            case (2 + $col_adjust) :
179
                $sorting = GradebookDataGenerator :: GDG_SORT_DESCRIPTION;
180
                break;
181
            case (3 + $col_adjust) :
182
                $sorting = GradebookDataGenerator :: GDG_SORT_WEIGHT;
183
                break;
184
            case (4 + $col_adjust) :
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...
185
                $sorting = GradebookDataGenerator :: GDG_SORT_DATE;
186
            case (5 + $col_adjust) :
187
                $sorting = GradebookDataGenerator :: GDG_SORT_ID;
188
                break;
189
        }
190
191
        if ($this->direction == 'DESC') {
192
            $sorting |= GradebookDataGenerator :: GDG_SORT_DESC;
193
        } else {
194
            $sorting |= GradebookDataGenerator :: GDG_SORT_ASC;
195
        }
196
197
        // Status of user in course.
198
        $user_id = $this->userId;
199
        $course_code = api_get_course_id();
200
        $session_id = api_get_session_id();
201
        $status_user = api_get_status_of_user_in_course(
202
            api_get_user_id(),
203
            api_get_course_int_id()
204
        );
205
206
        if (empty($session_id)) {
207
            $statusToFilter = STUDENT;
208
        } else {
209
            $statusToFilter = 0;
210
        }
211
212
        if (empty($this->studentList)) {
213
                $studentList = CourseManager::get_user_list_from_course_code(
214
                    $course_code,
215
                    $session_id,
216
                    null,
217
                    null,
218
                    $statusToFilter
219
                );
220
            $this->studentList = $studentList;
221
        }
222
223
        $this->datagen->userId = $this->userId;
224
225
        $data_array = $this->datagen->get_data(
226
            $sorting,
227
            $from,
228
            $this->per_page,
229
            false,
230
            $this->studentList
231
        );
232
233
        // generate the data to display
234
        $sortable_data = array();
235
        $weight_total_links = 0;
236
        $main_categories = array();
237
        $main_cat = Category::load(
238
            null,
239
            null,
240
            $course_code,
241
            null,
242
            null,
243
            $session_id,
244
            'ORDER BY id'
245
        );
246
        $total_categories_weight = 0;
247
        $scoredisplay = ScoreDisplay :: instance();
248
249
        $totalResult = [0, 0];
250
        $totalBest = [0, 0];
251
        $totalAverage = [0, 0];
252
253
        $type = 'detail';
254
        if ($this->exportToPdf) {
255
            $type = 'simple';
256
        }
257
258
        // Categories.
259
        if (!empty($data_array))
260
        foreach ($data_array as $data) {
261
            // list of items inside the gradebook (exercises, lps, forums, etc)
262
            $row  = array();
263
            /** @var AbstractLink $item */
264
            $item = $mainCategory = $data[0];
265
266
            //if the item is invisible, wrap it in a span with class invisible
267
            $invisibility_span_open  = api_is_allowed_to_edit() && $item->is_visible() == '0' ? '<span class="invisible">' : '';
268
            $invisibility_span_close = api_is_allowed_to_edit() && $item->is_visible() == '0' ? '</span>' : '';
269
270
            // Id
271
            if ($this->teacherView) {
272
                if ($this->exportToPdf == false) {
273
                    $row[] = $this->build_id_column($item);
274
                }
275
            }
276
277
            // Type.
278
            $row[] = $this->build_type_column($item);
279
280
            // Name.
281
            if (get_class($item) == 'Category') {
282
                $row[] = $invisibility_span_open.'<strong>'.$item->get_name().'</strong>'.$invisibility_span_close;
283
                $main_categories[$item->get_id()]['name'] = $item->get_name();
284
            } else {
285
                $name = $this->build_name_link($item, $type);
286
                $row[] = $invisibility_span_open.$name. $invisibility_span_close;
287
                $main_categories[$item->get_id()]['name'] = $name;
288
            }
289
290
            $this->dataForGraph['categories'][] = $item->get_name();
291
292
            $main_categories[$item->get_id()]['weight']= $item->get_weight();
293
            $total_categories_weight += $item->get_weight();
294
295
            // Description.
296 View Code Duplication
            if ($this->exportToPdf == false) {
297
                $row[] = $invisibility_span_open.$data[2].$invisibility_span_close;
298
            }
299
300
            // Weight.
301
            $weight = $scoredisplay->display_score(
302
                array(
303
                    $data['3'],
304
                    $this->currentcat->get_weight(),
305
                ),
306
                SCORE_SIMPLE,
307
                SCORE_BOTH,
308
                true
309
            );
310
311
            if ($this->teacherView) {
312
                $row[] = $invisibility_span_open .Display::tag('p', $weight, array('class' => 'score')).$invisibility_span_close;
313
            } else {
314
                $row[] = $invisibility_span_open .$weight.$invisibility_span_close;
315
            }
316
317
            $category_weight = $item->get_weight();
318
            $mainCategoryWeight = $main_cat[0]->get_weight();
319
320
            if ($this->teacherView) {
321
                $weight_total_links += $data[3];
322 View Code Duplication
            } else {
323
                $cattotal = Category::load($_GET['selectcat']);
324
                $scoretotal = $cattotal[0]->calc_score($this->userId);
325
                $item_value = $scoredisplay->display_score($scoretotal, SCORE_SIMPLE);
326
            }
327
328
            // Edit (for admins).
329
            if ($this->teacherView) {
330
                $cat = new Category();
331
                $show_message = $cat->show_message_resource_delete($item->get_course_code());
332
                if ($show_message === false) {
333
                    $row[] = $this->build_edit_column($item);
334
                }
335
            } else {
336
                $score = $item->calc_score($this->userId);
337
338
                if (!empty($score[1])) {
339
                    $completeScore = $scoredisplay->display_score($score, SCORE_DIV_PERCENT);
340
                    $score = $score[0]/$score[1]*$item->get_weight();
341
                    $score = $scoredisplay->display_score(array($score, null), SCORE_SIMPLE);
342
                    $scoreToDisplay = Display::tip($score, $completeScore);
343
                } else {
344
                    $scoreToDisplay = '-';
345
                    $categoryScore = null;
346
                }
347
348
                // Students get the results and certificates columns
349
                //if (count($this->evals_links) > 0 && $status_user != 1) {
350
                if (1) {
351
                    $value_data = isset($data[4]) ? $data[4] : null;
352
                    $best = isset($data['best']) ? $data['best'] : null;
353
                    $average = isset($data['average']) ? $data['average'] : null;
354
                    $ranking = isset($data['ranking']) ? $data['ranking'] : null;
355
356
                    $totalResult = [
357
                        $totalResult[0] + $data['result_score_weight'][0],
358
                        $totalResult[1] + $data['result_score_weight'][1],
359
                    ];
360
361
                    $totalBest = [
362
                        $totalBest[0] + $data['best_score'][0],
363
                        $totalBest[1] + $data['best_score'][1],
364
                    ];
365
366
                    $totalAverage = [
367
                        $totalAverage[0] + $data['average_score'][0],
368
                        $totalAverage[1] + $data['average_score'][1],
369
                    ];
370
371
                    // Student result
372
                    $row[] = $value_data;
373
                    $totalResultAverageValue = strip_tags($scoredisplay->display_score($totalResult, SCORE_AVERAGE));
374
                    $this->dataForGraph['my_result'][] = (float) str_replace('%', '', $totalResultAverageValue);
375
                    $totalAverageValue = strip_tags($scoredisplay->display_score($totalAverage, SCORE_AVERAGE));
376
                    $this->dataForGraph['average'][] =  (float) str_replace('%', '', $totalAverageValue);
377
                    // Ranking
378
                    $row[] = $ranking;
379
                    // Best
380
                    $row[] = $best;
381
                    // Average
382
                    $row[] = $average;
383
384
                    if (get_class($item) == 'Category') {
385
                        if ($this->exportToPdf == false) {
386
                            $row[] = $this->build_edit_column($item);
387
                        }
388
                    }
389
                } else {
390
                    $row[] = $scoreToDisplay;
391
392
                    if (!empty($this->cats)) {
393
                        if ($this->exportToPdf == false) {
394
                            $row[] = $this->build_edit_column($item);
395
                        }
396
                    }
397
                }
398
            }
399
400
            // Category added.
401
            $sortable_data[] = $row;
402
403
            // Loading children
404
            if (get_class($item) == 'Category') {
405
                $course_code = api_get_course_id();
406
                $session_id = api_get_session_id();
407
                $parent_id = $item->get_id();
408
                $cats = Category::load(
409
                    $parent_id,
410
                    null,
411
                    null,
412
                    null,
413
                    null,
414
                    null
415
                );
416
417
                if (isset($cats[0])) {
418
                    $allcat  = $cats[0]->get_subcategories($this->userId, $course_code, $session_id);
419
                    $alleval = $cats[0]->get_evaluations($this->userId);
420
                    $alllink = $cats[0]->get_links($this->userId);
421
422
                    $sub_cat_info = new GradebookDataGenerator($allcat, $alleval, $alllink);
423
                    $sub_cat_info->userId = $user_id;
424
425
                    $data_array2 = $sub_cat_info->get_data(
426
                        $sorting,
427
                        $from,
428
                        $this->per_page,
429
                        false,
430
                        $this->studentList
431
                    );
432
                    $total_weight = 0;
433
434
                    // Links.
435
                    foreach ($data_array2 as $data) {
436
437
                        $row = array();
438
                        $item = $data[0];
439
440
                        //if the item is invisible, wrap it in a span with class invisible
441
                        $invisibility_span_open = api_is_allowed_to_edit() && $item->is_visible() == '0' ? '<span class="invisible">' : '';
442
                        $invisibility_span_close = api_is_allowed_to_edit() && $item->is_visible() == '0' ? '</span>' : '';
443
444
                        if (isset($item)) {
445
                            $main_categories[$parent_id]['children'][$item->get_id()]['name'] = $item->get_name();
446
                            $main_categories[$parent_id]['children'][$item->get_id()]['weight'] = $item->get_weight();
447
                        }
448
449
                        if ($this->teacherView) {
450
                            if ($this->exportToPdf == false) {
451
                                $row[] = $this->build_id_column($item);
452
                            }
453
                        }
454
455
                        // Type
456
                        $row[] = $this->build_type_column($item, array('style' => 'padding-left:5px'));
457
458
                        // Name.
459
                        $row[] = $invisibility_span_open."&nbsp;&nbsp;&nbsp;  ".$this->build_name_link($item, $type) . $invisibility_span_close;
460
461
                        // Description.
462 View Code Duplication
                        if ($this->exportToPdf == false) {
463
                            $row[] = $invisibility_span_open.$data[2].$invisibility_span_close;
464
                        }
465
466
                        $weight = $data[3];
467
                        $total_weight += $weight;
468
469
                        // Weight
470
                        $row[] = $invisibility_span_open.$weight.$invisibility_span_close;
471
472 View Code Duplication
                        if ($this->teacherView) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

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

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

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

could be turned into

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

This is much more concise to read.

Loading history...
473
                            //$weight_total_links += intval($data[3]);
474
                        } else {
475
                            $cattotal = Category::load($_GET['selectcat']);
476
                            $scoretotal = $cattotal[0]->calc_score($this->userId);
477
                            $item_value = $scoretotal[0];
478
                        }
479
480
                        // Admins get an edit column.
481
                        if (api_is_allowed_to_edit(null, true) &&
482
                            isset($_GET['user_id']) == false &&
483
                            (isset($_GET['action']) && $_GET['action'] != 'export_all' || !isset($_GET['action'])
484
                            )
485
                        ) {
486
                            $cat = new Category();
487
                            $show_message = $cat->show_message_resource_delete($item->get_course_code());
488
                            if ($show_message === false) {
489
                                if ($this->exportToPdf == false) {
490
                                    $row[] = $this->build_edit_column($item);
491
                                }
492
                            }
493
                        } else {
494
                            // Students get the results and certificates columns
495
                            $eval_n_links = array_merge($alleval, $alllink);
496
497
                            if (count($eval_n_links)> 0) {
498
                                $value_data = isset($data[4]) ? $data[4] : null;
499
500
                                if (!is_null($value_data)) {
501
                                    //$score = $item->calc_score(api_get_user_id());
502
                                    //$new_score = $data[3] * $score[0] / $score[1];
503
                                    //$new_score = floatval(number_format($new_score, api_get_setting('gradebook_number_decimals')));
504
505
                                    // Result
506
                                    $row[] = $value_data;
507
508
                                    $best = isset($data['best']) ? $data['best'] : null;
509
                                    $average = isset($data['average']) ? $data['average'] : null;
510
                                    $ranking = isset($data['ranking']) ? $data['ranking'] : null;
511
512
                                    // Ranking
513
                                    $row[] = $ranking;
514
                                    // Best
515
                                    $row[] = $best;
516
                                    // Average
517
                                    $row[] = $average;
518
                                }
519
                            }
520
521
                            if (!empty($cats)) {
522
                                if ($this->exportToPdf == false) {
523
                                    $row[] = null;
524
                                }
525
                            }
526
                        }
527
528
                        if ($this->exportToPdf == false) {
529
                            $row['child_of'] = $parent_id;
530
                        }
531
                        $sortable_data[] = $row;
532
                    }
533
534
                    // "Warning row"
535
                    if (!empty($data_array)) {
536
                        if ($this->teacherView) {
537
                            // Compare the category weight to the sum of all weights inside the category
538
                            if (intval($total_weight) == $category_weight) {
539
                                $label = null;
540
                                $total = GradebookUtils::score_badges(
541
                                    array(
542
                                        $total_weight.' / '.$category_weight,
543
                                        '100'
544
                                    )
545
                                );
546
                            } else {
547
                                $label = Display::return_icon(
548
                                    'warning.png',
549
                                    sprintf(get_lang('TotalWeightMustBeX'), $category_weight)
550
                                );
551
                                $total = Display::badge($total_weight.' / '.$category_weight, 'warning');
552
                            }
553
                            $row = array(
554
                                null,
555
                                null,
556
                                "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>".get_lang('SubTotal').'</h5>',
557
                                null,
558
                                $total.' '.$label,
559
                                'child_of' => $parent_id
560
                            );
561
                            $sortable_data[] = $row;
562
                        }
563
                    }
564
                }
565
            }
566
        } //end looping categories
567
568
        $main_weight = 0;
569
        if (count($main_cat) > 1) {
570
            /** @var Category $myCat */
571
            foreach ($main_cat as $myCat) {
572
                $myParentId = $myCat->get_parent_id();
573
                if ($myParentId == 0) {
574
                    $main_weight = intval($myCat->get_weight());
575
                }
576
            }
577
        }
578
579
        if ($this->teacherView) {
580
            // Total for teacher.
581
            if (count($main_cat) > 1) {
582
583
                if (intval($total_categories_weight) == $main_weight) {
584
                    $total = GradebookUtils::score_badges(
585
                        array(
586
                            $total_categories_weight.' / '.$main_weight,
587
                            '100'
588
                        )
589
                    );
590
                } else {
591
                    $total = Display::badge($total_categories_weight.' / '.$main_weight, 'warning');
592
                }
593
                $row = array(
594
                    null,
595
                    null,
596
                    '<strong>' . get_lang('Total') . '</strong>',
597
                    null,
598
                    $total
599
                );
600
                $sortable_data[] = $row;
601
            }
602
        } else {
603
            // Total for student.
604
            if (count($main_cat) > 1) {
605
                $main_weight = intval($main_cat[0]->get_weight());
606
607
                $global = null;
608
                $average = null;
609
                // Overwrite main weight
610
                $totalResult[1] = $main_weight;
611
612
                $totalResult = $scoredisplay->display_score(
613
                    $totalResult,
614
                    SCORE_DIV
615
                );
616
617
                $totalRanking = array();
618
                $invalidateRanking = true;
619
                $average = 0;
620
                foreach ($this->studentList as $student) {
621
                    $score = $main_cat[0]->calc_score($student['user_id']);
622
                    if (!empty($score[0])) {
623
                        $invalidateRanking = false;
624
                    }
625
                    $totalRanking[$student['user_id']] = $score[0];
626
                    $average += $score[0];
627
                }
628
629
                $totalRanking = AbstractLink::getCurrentUserRanking($user_id, $totalRanking);
630
631
                $totalRanking = $scoredisplay->display_score(
632
                    $totalRanking,
633
                    SCORE_DIV,
634
                    SCORE_BOTH,
635
                    true
636
                );
637
638
                if ($invalidateRanking) {
639
                    $totalRanking = null;
640
                }
641
642
                // Overwrite main weight
643
                $totalBest[1] = $main_weight;
644
645
                $totalBest = $scoredisplay->display_score(
646
                    $totalBest,
647
                    SCORE_DIV,
648
                    SCORE_BOTH,
649
                    true
650
                );
651
652
                // Overwrite main weight
653
                $totalAverage[0] = $average / count($this->studentList);
654
                $totalAverage[1] = $main_weight;
655
656
                $totalAverage = $scoredisplay->display_score(
657
                    $totalAverage,
658
                    SCORE_DIV,
659
                    SCORE_BOTH,
660
                    true
661
                );
662
663
                if ($this->exportToPdf) {
664
                    $row = array(
665
                        null,
666
                        '<h3>' . get_lang('Total') . '</h3>',
667
                        $main_weight,
668
                        $totalResult,
669
                        $totalRanking,
670
                        $totalBest,
671
                        $totalAverage,
672
                    );
673
                } else {
674
                    $row = array(
675
                        null,
676
                        '<h3>' . get_lang('Total') . '</h3>',
677
                        null,
678
                        $main_weight,
679
                        $totalResult,
680
                        $totalRanking,
681
                        $totalBest,
682
                        $totalAverage,
683
                    );
684
                }
685
686
                $sortable_data[] = $row;
687
            }
688
        }
689
690
        // Warning messages
691
        $view = isset($_GET['view']) ? $_GET['view']: null;
692
693
        if ($this->teacherView) {
694
            if (isset($_GET['selectcat']) &&
695
                $_GET['selectcat'] > 0 &&
696
                $view <> 'presence'
697
            ) {
698
                $id_cat = intval($_GET['selectcat']);
699
                $category = Category::load($id_cat);
700
701
                $weight_category = intval($this->build_weight($category[0]));
702
703
                $course_code = $this->build_course_code($category[0]);
704
                $weight_total_links  = round($weight_total_links);
705
706
                if ($weight_total_links > $weight_category ||
707
                    $weight_total_links < $weight_category ||
708
                    $weight_total_links > $weight_category
709
                ) {
710
                    $warning_message = sprintf(get_lang('TotalWeightMustBeX'), $weight_category);
711
                    $modify_icons  = '<a href="gradebook_edit_cat.php?editcat='.$id_cat.'&cidReq='.$course_code.'&id_session='.api_get_session_id().'">'.
712
                        Display::return_icon('edit.png', $warning_message, array(), ICON_SIZE_SMALL).'</a>';
713
                    $warning_message .= $modify_icons;
714
                    Display::display_warning_message($warning_message, false);
715
                }
716
717
                $content_html = DocumentManager::replace_user_info_into_html(
718
                    api_get_user_id(),
719
                    $course_code,
720
                    api_get_session_id()
721
                );
722
723
                if (!empty($content_html)) {
724
                    $new_content = explode('</head>',$content_html['content']);
725
                }
726
727
                if (empty($new_content[0])) {
728
                    // Set default certificate
729
                    $courseData = api_get_course_info($course_code);
730
                    DocumentManager::generateDefaultCertificate($courseData);
731
                }
732
            }
733
734
            if (empty($_GET['selectcat'])) {
735
                $categories = Category :: load();
736
                $weight_categories = $certificate_min_scores = $course_codes = array();
737
                foreach ($categories as $category) {
738
                    $course_code_category = $this->build_course_code($category);
739
                    if (!empty($course_code)) {
740 View Code Duplication
                        if ($course_code_category == $course_code) {
741
                            $weight_categories[] = intval($this->build_weight($category));
742
                            $certificate_min_scores[] = intval($this->build_certificate_min_score($category));
743
                            $course_codes[] = $course_code;
744
                            break;
745
                        }
746 View Code Duplication
                    } else {
747
                        $weight_categories[] = intval($this->build_weight($category));
748
                        $certificate_min_scores[] = intval($this->build_certificate_min_score($category));
749
                        $course_codes[] = $course_code_category;
750
                    }
751
                }
752
753
                if (is_array($weight_categories) &&
754
                    is_array($certificate_min_scores) &&
755
                    is_array($course_codes)
756
                ) {
757
                    $warning_message = '';
758
                    for ($x = 0; $x<count($weight_categories);$x++) {
759
                        $weight_category = intval($weight_categories[$x]);
760
                        $certificate_min_score = intval($certificate_min_scores[$x]);
761
                        $course_code = $course_codes[$x];
762
763
                        if (empty($certificate_min_score) ||
764
                            ($certificate_min_score > $weight_category)
765
                        ) {
766
                            $warning_message .= $course_code .'&nbsp;-&nbsp;'.get_lang('CertificateMinimunScoreIsRequiredAndMustNotBeMoreThan').'&nbsp;'.$weight_category.'<br />';
767
                        }
768
                    }
769
770
                    if (!empty($warning_message)) {
771
                        Display::display_warning_message($warning_message,false);
772
                    }
773
                }
774
            }
775
        }
776
777
        return $sortable_data;
778
    }
779
780
781
    /**
782
     * @return array
783
     */
784
    private function getDataForGraph()
785
    {
786
        return $this->dataForGraph;
787
    }
788
789
    /**
790
     * @return string
791
     */
792
    public function getGraph()
793
    {
794
        $data = $this->getDataForGraph();
795
        if (!empty($data) &&
796
            isset($data['categories']) &&
797
            isset($data['my_result']) &&
798
            isset($data['average'])
799
        ) {
800
            $dataSet = new pData();
801
            $dataSet->addPoints($data['my_result'], get_lang('Me'));
802
            // In order to generate random values
803
            // $data['average'] = array(rand(0,50), rand(0,50));
804
            $dataSet->addPoints($data['average'], get_lang('Average'));
805
            $dataSet->addPoints($data['categories'], 'categories');
806
807
            $dataSet->setAbscissa("categories");
808
            $xSize = 600;
809
            $ySize = 400;
810
            $pChart = new pImage($xSize, $ySize, $dataSet);
811
            /* Turn of Antialiasing */
812
            $pChart->Antialias = false;
813
814
            /* Add a border to the picture */
815
            $pChart->drawRectangle(0,0,$xSize-10,$ySize-10,array("R"=>0,"G"=>0,"B"=>0));
816
817
            $pChart->drawText(10,16,get_lang('Results'),array("FontSize"=>11,"Align"=>TEXT_ALIGN_BOTTOMLEFT));
818
819
            $pChart->setGraphArea(50, 30, $xSize-50, $ySize-50);
820
821
            $pChart->setFontProperties(
822
                array(
823
                    'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
824
                    'FontSize' => 10,
825
                )
826
            );
827
828
            /* Draw the scale */
829
            $scaleSettings = array(
830
                "XMargin" => 10,
831
                "YMargin" => 10,
832
                "Floating" => true,
833
                "GridR" => 200,
834
                "GridG" => 200,
835
                "GridB" => 200,
836
                "DrawSubTicks" => true,
837
                "CycleBackground" => true,
838
            );
839
            $pChart->drawScale($scaleSettings);
840
841
            /* Draw the line chart */
842
            $pChart->drawLineChart();
843
            $pChart->drawPlotChart(array("DisplayValues"=>TRUE,"PlotBorder"=>TRUE,"BorderSize"=>2,"Surrounding"=>-60,"BorderAlpha"=>80));
844
845
            /* Write the chart legend */
846
            $pChart->drawLegend(
847
                $xSize - 180,
848
                9,
849
                array(
850
                    "Style" => LEGEND_NOBORDER,
851
                    "Mode" => LEGEND_HORIZONTAL,
852
                    "FontR" => 0,
853
                    "FontG" => 0,
854
                    "FontB" => 0,
855
                )
856
            );
857
858
            $cachePath = api_get_path(SYS_ARCHIVE_PATH);
859
            $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
860
            $chartHash = $myCache->getHash($dataSet);
861
862
            $myCache->writeToCache($chartHash, $pChart);
863
            $imgSysPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
864
            $myCache->saveFromCache($chartHash, $imgSysPath);
865
            $imgWebPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
866
867
            if (file_exists($imgSysPath)) {
868
                $result = '<div id="contentArea" style="text-align: center;" >';
869
                $result .= '<img src="' . $imgWebPath.'" >';
870
                $result .= '</div>';
871
                return $result;
872
            }
873
        }
874
875
        return '';
876
    }
877
878
    /**
879
     * @param $item
880
     * @return mixed
881
     */
882
    private function build_certificate_min_score($item)
883
    {
884
        return $item->get_certificate_min_score();
885
    }
886
887
    /**
888
     * @param $item
889
     * @return mixed
890
     */
891
    private function build_weight($item)
892
    {
893
        return $item->get_weight();
894
    }
895
896
    /**
897
     * @param $item
898
     * @return mixed
899
     */
900
    private function build_course_code($item)
901
    {
902
        return $item->get_course_code();
903
    }
904
905
    /**
906
     * @param $item
907
     * @return string
908
     */
909
    private function build_id_column($item)
910
    {
911
        switch ($item->get_item_type()) {
912
            // category
913
            case 'C' :
914
                return 'CATE' . $item->get_id();
915
            // evaluation
916
            case 'E' :
917
                return 'EVAL' . $item->get_id();
918
            // link
919
            case 'L' :
920
                return 'LINK' . $item->get_id();
921
        }
922
    }
923
924
    /**
925
     * @param $item
926
     * @param array $attributes
927
     * @return string
928
     */
929
    private function build_type_column($item, $attributes = array())
930
    {
931
        return GradebookUtils::build_type_icon_tag($item->get_icon_name(), $attributes);
932
    }
933
934
    /**
935
     * Generate name column
936
     * @param GradebookItem $item
937
     * @param string $type simple|detail
938
     * @return string
939
     */
940
    private function build_name_link($item, $type = 'detail')
941
    {
942
        $view = isset($_GET['view']) ? Security::remove_XSS($_GET['view']) : null;
943
        $categoryId = $item->getCategory()->get_id();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GradebookItem as the method getCategory() does only exist in the following implementations of said interface: AbstractLink, AttendanceLink, DropboxLink, EvalLink, Evaluation, ExerciseLink, ForumThreadLink, LearnpathLink, StudentPublicationLink, SurveyLink.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
944
945
        switch ($item->get_item_type()) {
946
            // category
947
            case 'C' :
948
                $prms_uri='?selectcat=' . $item->get_id() . '&amp;view='.$view;
949
950
                if (isset($_GET['isStudentView'])) {
951
                    if ( isset($is_student) || ( isset($_SESSION['studentview']) && $_SESSION['studentview']=='studentview') ) {
0 ignored issues
show
Bug introduced by
The variable $is_student seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
952
                        $prms_uri=$prms_uri.'&amp;isStudentView='.Security::remove_XSS($_GET['isStudentView']);
953
                    }
954
                }
955
956
                $cat = new Category();
957
                $show_message=$cat->show_message_resource_delete($item->get_course_code());
958
                return '&nbsp;<a href="'.Security::remove_XSS($_SESSION['gradebook_dest']).$prms_uri.'">'
959
                . $item->get_name()
960
                . '</a>'
961
                . ($item->is_course() ? ' &nbsp;[' . $item->get_course_code() . ']'.$show_message : '');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GradebookItem as the method is_course() does only exist in the following implementations of said interface: Category.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
962
                // evaluation
963
            case 'E' :
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...
964
                $cat = new Category();
965
                $course_id = CourseManager::get_course_by_category($categoryId);
966
                $show_message = $cat->show_message_resource_delete($course_id);
967
968
                // course/platform admin can go to the view_results page
969
                if (api_is_allowed_to_edit() && $show_message===false) {
970
                    if ($item->get_type() == 'presence') {
971
                        return '&nbsp;'
972
                        . '<a href="gradebook_view_result.php?cidReq='.$course_id.'&amp;selecteval=' . $item->get_id() . '">'
973
                        . $item->get_name()
974
                        . '</a>';
975
                    } else {
976
                        $extra = Display::label(get_lang('Evaluation'));
977
                        if ($type == 'simple') {
978
                            $extra = '';
979
                        }
980
                        return '&nbsp;'
981
                        . '<a href="gradebook_view_result.php?' . api_get_cidreq() . '&selecteval=' . $item->get_id() . '">'
982
                        . $item->get_name()
983
                        . '</a>&nbsp;'.$extra;
984
                    }
985
                } elseif (ScoreDisplay :: instance()->is_custom() && $show_message===false) {
986
                    // students can go to the statistics page (if custom display enabled)
987
                    return '&nbsp;'
988
                    . '<a href="gradebook_statistics.php?' . api_get_cidreq() . '&selecteval=' . $item->get_id() . '">'
989
                    . $item->get_name()
990
                    . '</a>';
991
992
                } elseif ($show_message === false && !api_is_allowed_to_edit() && !ScoreDisplay :: instance()->is_custom()) {
993
                    return '&nbsp;'
994
                    . '<a href="gradebook_statistics.php?' . api_get_cidreq() . '&selecteval=' . $item->get_id() . '">'
995
                    . $item->get_name()
996
                    . '</a>';
997
                } else {
998
                    return '['.get_lang('Evaluation').']&nbsp;&nbsp;'.$item->get_name().$show_message;
999
                }
1000
            case 'L':
1001
                // link
1002
                $cat = new Category();
1003
                $course_id = CourseManager::get_course_by_category($categoryId);
1004
                $show_message = $cat->show_message_resource_delete($course_id);
1005
1006
                $url = $item->get_link();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GradebookItem as the method get_link() does only exist in the following implementations of said interface: AbstractLink, AttendanceLink, DropboxLink, EvalLink, ExerciseLink, ForumThreadLink, LearnpathLink, StudentPublicationLink, SurveyLink.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
1007
1008
                if (isset($url) && $show_message === false) {
1009
                    $text = '&nbsp;<a href="' . $item->get_link() . '">'
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GradebookItem as the method get_link() does only exist in the following implementations of said interface: AbstractLink, AttendanceLink, DropboxLink, EvalLink, ExerciseLink, ForumThreadLink, LearnpathLink, StudentPublicationLink, SurveyLink.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
1010
                        . $item->get_name()
1011
                        . '</a>';
1012
                } else {
1013
                    $text = $item->get_name();
1014
                }
1015
1016
                $extra = Display::label($item->get_type_name(), 'info');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GradebookItem as the method get_type_name() does only exist in the following implementations of said interface: AbstractLink, AttendanceLink, DropboxLink, EvalLink, ExerciseLink, ForumThreadLink, LearnpathLink, StudentPublicationLink, SurveyLink.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
1017
                if ($type == 'simple') {
1018
                    $extra = '';
1019
                }
1020
1021
                $text .= "&nbsp;".$extra.$show_message;
1022
                $cc = $this->currentcat->get_course_code();
1023
                if (empty($cc)) {
1024
                    $text .= '&nbsp;[<a href="'.api_get_path(REL_COURSE_PATH).$item->get_course_code().'/">'.$item->get_course_code().'</a>]';
1025
                }
1026
                return $text;
1027
        }
1028
    }
1029
1030
    /**
1031
     * @param $item
1032
     * @return null|string
1033
     */
1034
    private function build_edit_column($item)
1035
    {
1036
        switch ($item->get_item_type()) {
1037
            // category
1038
            case 'C' :
1039
                return GradebookUtils::build_edit_icons_cat($item, $this->currentcat);
1040
            // evaluation
1041
            case 'E' :
1042
                return GradebookUtils::build_edit_icons_eval($item, $this->currentcat->get_id());
1043
            // link
1044
            case 'L' :
1045
                return GradebookUtils::build_edit_icons_link($item, $this->currentcat->get_id());
1046
        }
1047
    }
1048
}
1049