Passed
Push — master ( 78cd0a...f41061 )
by Julito
10:08
created

GradebookTable::build_weight()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see license.txt */
3
4
use ChamiloSession as Session;
5
use CpChart\Cache as pCache;
6
use CpChart\Data as pData;
7
use CpChart\Image as pImage;
8
9
/**
10
 * GradebookTable Class
11
 * Table to display categories, evaluations and links.
12
 *
13
 * @author Stijn Konings
14
 * @author Bert Steppé (refactored, optimised)
15
 *
16
 * @package chamilo.gradebook
17
 */
18
class GradebookTable extends SortableTable
19
{
20
    public $cats;
21
    public $exportToPdf;
22
    public $teacherView;
23
    public $userId;
24
    public $studentList = [];
25
    private $currentcat;
26
    private $datagen;
27
    private $evals_links;
28
    private $dataForGraph;
29
    /**
30
     * @var array Indicates which columns should be shown in gradebook
31
     *
32
     * @example [1] For add Ranking column
33
     *          [2] For add Best Score column
34
     *          [3] For add Average column
35
     */
36
    private $loadStats = [];
37
38
    /**
39
     * GradebookTable constructor.
40
     *
41
     * @param Category $currentcat
42
     * @param array    $cats
43
     * @param array    $evals
44
     * @param array    $links
45
     * @param null     $addparams
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $addparams is correct as it would always require null to be passed?
Loading history...
46
     * @param bool     $exportToPdf
47
     * @param null     $showTeacherView
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $showTeacherView is correct as it would always require null to be passed?
Loading history...
48
     * @param int      $userId
49
     * @param array    $studentList
50
     * @param array    $loadStats
51
     */
52
    public function __construct(
53
        $currentcat,
54
        $cats = [],
55
        $evals = [],
56
        $links = [],
57
        $addparams = null,
58
        $exportToPdf = false,
59
        $showTeacherView = null,
60
        $userId = null,
61
        $studentList = [],
62
        array $loadStats = []
63
    ) {
64
        $this->teacherView = is_null($showTeacherView) ? api_is_allowed_to_edit(null, true) : $showTeacherView;
65
        $this->userId = is_null($userId) ? api_get_user_id() : $userId;
66
        $this->exportToPdf = $exportToPdf;
67
        $this->studentList = $studentList;
68
69
        parent::__construct(
70
            'gradebooklist',
71
            null,
72
            null,
73
            api_is_allowed_to_edit() ? 1 : 0,
74
            20,
75
            'ASC',
76
            'gradebook_list'
77
        );
78
79
        $this->evals_links = array_merge($evals, $links);
80
        $this->currentcat = $currentcat;
81
        $this->cats = $cats;
82
        $this->loadStats = $loadStats;
83
        $this->datagen = new GradebookDataGenerator($cats, $evals, $links);
84
        $this->datagen->preLoadDataKey = $this->getPreloadDataKey();
85
86
        $this->datagen->hidePercentage = api_get_configuration_value('hide_gradebook_percentage_user_result');
87
88
        if (!empty($userId)) {
89
            $this->datagen->userId = $userId;
90
        }
91
92
        if (isset($addparams)) {
93
            $this->set_additional_parameters($addparams);
94
        }
95
96
        $column = 0;
97
        if ($this->teacherView) {
98
            if ($this->exportToPdf == false) {
99
                $this->set_header($column++, '', '', 'width="25px"');
100
            }
101
        }
102
103
        $this->set_header($column++, get_lang('Type'), '', 'width="35px"');
104
        $this->set_header($column++, get_lang('Name'), false);
105
106
        if ($this->exportToPdf == false) {
107
            $this->set_header($column++, get_lang('Description'), false);
108
        }
109
110
        $model = ExerciseLib::getCourseScoreModel();
111
112
        $this->set_header(
113
            $column++,
114
            get_lang('Weight'),
115
            '',
116
            'width="100px"'
117
        );
118
119
        if (!$this->teacherView) {
120
            $this->set_header($column++, get_lang('Result'), false);
121
        }
122
123
        if (empty($model)) {
124
            if (in_array(1, $this->loadStats)) {
125
                $this->set_header($column++, get_lang('Ranking'), false);
126
            }
127
            if (in_array(2, $this->loadStats)) {
128
                $this->set_header($column++, get_lang('BestScore'), false);
129
            }
130
            if (in_array(3, $this->loadStats)) {
131
                $this->set_header($column++, get_lang('Average'), false);
132
            }
133
        }
134
135
        if ($this->teacherView) {
136
        } else {
137
            if (!empty($cats)) {
138
                if ($this->exportToPdf == false) {
139
                    $this->set_header($column++, get_lang('Actions'), false);
140
                }
141
            }
142
        }
143
144
        // Deactivates the odd/even alt rows in order that the +/- buttons work see #4047
145
        $this->odd_even_rows_enabled = false;
146
147
        // Admins get an edit column.
148
        if ($this->teacherView) {
149
            $this->set_header($column++, get_lang('Modify'), false, 'width="195px"');
150
            // Actions on multiple selected documents.
151
            $this->set_form_actions(
152
                [
153
                    'setvisible' => get_lang('SetVisible'),
154
                    'setinvisible' => get_lang('SetInvisible'),
155
                    'deleted' => get_lang('DeleteSelected'),
156
                ]
157
            );
158
        } else {
159
            if (empty($_GET['selectcat']) && !$this->teacherView) {
160
                if ($this->exportToPdf == false) {
161
                    $this->set_header(
162
                        $column++,
163
                        get_lang('Certificates'),
164
                        false
165
                    );
166
                }
167
            }
168
        }
169
    }
170
171
    /**
172
     * @return GradebookDataGenerator
173
     */
174
    public function get_data()
175
    {
176
        return $this->datagen;
177
    }
178
179
    /**
180
     * Function used by SortableTable to get total number of items in the table.
181
     *
182
     * @return int
183
     */
184
    public function get_total_number_of_items()
185
    {
186
        return $this->datagen->get_total_items_count();
187
    }
188
189
    /**
190
     * @return string
191
     */
192
    public function getPreloadDataKey()
193
    {
194
        return 'default_data_'.api_get_course_id().'_'.api_get_session_id();
195
    }
196
197
    public function preloadData()
198
    {
199
        $allitems = $this->datagen->items;
200
        usort($allitems, ['GradebookDataGenerator', 'sort_by_name']);
201
        //$visibleItems = $this->datagen->items;
202
        $visibleItems = array_merge($this->datagen->items, $this->evals_links);
203
204
        //Session::erase($this->getPreloadDataKey());
205
        $defaultDataFromSession = Session::read($this->getPreloadDataKey());
206
        if (empty($defaultDataFromSession)) {
207
            $defaultData = [];
208
            /** @var GradebookItem $item */
209
            foreach ($visibleItems as $item) {
210
                $item->setStudentList($this->studentList);
211
                $itemType = get_class($item);
212
                switch ($itemType) {
213
                    case 'Evaluation':
214
                        // Best
215
                        $best = $this->datagen->buildBestResultColumn($item);
216
                        $defaultData[$item->get_id()]['best'] = $best;
217
                        // Average
218
                        $average = $this->datagen->buildAverageResultColumn($item);
219
                        $defaultData[$item->get_id()]['average'] = $average;
220
                        break;
221
                    case 'ExerciseLink':
222
                        /** @var ExerciseLink $item */
223
                        // Best
224
                        $best = $this->datagen->buildBestResultColumn($item);
225
                        $defaultData[$item->get_id()]['best'] = $best;
226
                        // Average
227
                        $average = $this->datagen->buildAverageResultColumn($item);
228
                        $defaultData[$item->get_id()]['average'] = $average;
229
230
                        // Ranking
231
                        /*if (!empty($this->studentList)) {
232
                            $invalidateRanking = true;
233
                            foreach ($this->studentList as $user) {
234
                                $score = $this->datagen->build_result_column(
235
                                    $user['user_id'],
236
                                    $item,
237
                                    false,
238
                                    true
239
                                );
240
                                if (!empty($score['score'])) {
241
                                    $invalidateRanking = false;
242
                                }
243
                                $rankingStudentList[$user['user_id']] = $score['score'][0];
244
                                $defaultData[$item->get_id()]['ranking'] = $rankingStudentList;
245
                                $defaultData[$item->get_id()]['ranking_invalidate'] = $invalidateRanking;
246
                            }
247
                        }*/
248
                        break;
249
                    default:
250
                        // Best
251
                        $best = $this->datagen->buildBestResultColumn($item);
252
                        $defaultData[$item->get_id()]['best'] = $best;
253
254
                        // Average
255
                        $average = $this->datagen->buildAverageResultColumn($item);
256
                        $defaultData[$item->get_id()]['average'] = $average;
257
258
                        // Ranking
259
                        if (!empty($this->studentList)) {
260
                            $invalidateRanking = true;
261
                            foreach ($this->studentList as $user) {
262
                                $score = $this->datagen->build_result_column(
263
                                    $user['user_id'],
264
                                    $item,
265
                                    false,
266
                                    true
267
                                );
268
                                if (!empty($score['score'])) {
269
                                    $invalidateRanking = false;
270
                                }
271
                                $rankingStudentList[$user['user_id']] = $score['score'][0];
272
                                $defaultData[$item->get_id()]['ranking'] = $rankingStudentList;
273
                                $defaultData[$item->get_id()]['ranking_invalidate'] = $invalidateRanking;
274
                            }
275
                            //exit;
276
                        }
277
                        break;
278
                }
279
            }
280
            Session::write($this->getPreloadDataKey(), $defaultData);
281
        } else {
282
            $defaultData = $defaultDataFromSession;
283
        }
284
285
        return $defaultData;
286
    }
287
288
    /**
289
     * Function used by SortableTable to generate the data to display.
290
     *
291
     * @param int    $from
292
     * @param int    $per_page
293
     * @param int    $column
294
     * @param string $direction
295
     * @param int    $sort
296
     *
297
     * @return array|mixed
298
     */
299
    public function get_table_data($from = 1, $per_page = null, $column = null, $direction = null, $sort = null)
300
    {
301
        //variables load in index.php
302
        global $certificate_min_score;
303
304
        $isAllowedToEdit = api_is_allowed_to_edit();
305
        // determine sorting type
306
        $col_adjust = $isAllowedToEdit ? 1 : 0;
307
        // By id
308
        $this->column = 5;
309
310
        switch ($this->column) {
311
            // Type
312
            case 0 + $col_adjust:
313
                $sorting = GradebookDataGenerator::GDG_SORT_TYPE;
314
                break;
315
            case 1 + $col_adjust:
316
                $sorting = GradebookDataGenerator::GDG_SORT_NAME;
317
                break;
318
            case 2 + $col_adjust:
319
                $sorting = GradebookDataGenerator::GDG_SORT_DESCRIPTION;
320
                break;
321
            case 3 + $col_adjust:
322
                $sorting = GradebookDataGenerator::GDG_SORT_WEIGHT;
323
                break;
324
            case 4 + $col_adjust:
325
                $sorting = GradebookDataGenerator::GDG_SORT_DATE;
326
                break;
327
            case 5 + $col_adjust:
328
                $sorting = GradebookDataGenerator::GDG_SORT_ID;
329
                break;
330
        }
331
332
        if ($this->direction == 'DESC') {
333
            $sorting |= GradebookDataGenerator::GDG_SORT_DESC;
334
        } else {
335
            $sorting |= GradebookDataGenerator::GDG_SORT_ASC;
336
        }
337
338
        // Status of user in course.
339
        $user_id = $this->userId;
340
        $course_code = api_get_course_id();
341
        $session_id = api_get_session_id();
342
343
        $statusToFilter = 0;
344
        if (empty($session_id)) {
345
            $statusToFilter = STUDENT;
346
        }
347
348
        if (empty($this->studentList) && $this->loadStats) {
349
            $studentList = CourseManager::get_user_list_from_course_code(
350
                $course_code,
351
                $session_id,
352
                null,
353
                null,
354
                $statusToFilter
355
            );
356
            $this->studentList = $studentList;
357
        }
358
359
        $this->datagen->userId = $this->userId;
360
        $data_array = $this->datagen->get_data(
361
            $sorting,
362
            $from,
363
            $this->per_page,
364
            false,
365
            $this->studentList,
366
            $this->loadStats
367
        );
368
369
        // generate the data to display
370
        $sortable_data = [];
371
        $weight_total_links = 0;
372
        $main_cat = Category::load(
373
            null,
374
            null,
375
            $course_code,
376
            null,
377
            null,
378
            $session_id,
379
            'ORDER BY id'
380
        );
381
382
        $total_categories_weight = 0;
383
        $scoredisplay = ScoreDisplay::instance();
384
385
        $totalUserResult = [0, 0];
386
        $totalBest = [0, 0];
387
        $totalAverage = [0, 0];
388
389
        $type = 'detail';
390
        if ($this->exportToPdf) {
391
            $type = 'simple';
392
        }
393
394
        $model = ExerciseLib::getCourseScoreModel();
395
        $userExerciseScoreInCategory = api_get_configuration_value(
396
            'gradebook_use_exercise_score_settings_in_categories'
397
        );
398
399
        $course_code = api_get_course_id();
400
        $session_id = api_get_session_id();
401
        $defaultData = Session::read($this->getPreloadDataKey());
402
403
        // Categories.
404
        if (!empty($data_array)) {
405
            foreach ($data_array as $data) {
406
                // list of items inside the gradebook (exercises, lps, forums, etc)
407
                $row = [];
408
                /** @var AbstractLink $item */
409
                $item = $mainCategory = $data[0];
410
411
                // If the item is invisible, wrap it in a span with class invisible
412
                $invisibility_span_open = $isAllowedToEdit && $item->is_visible() == '0' ? '<span class="text-muted">' : '';
413
                $invisibility_span_close = $isAllowedToEdit && $item->is_visible() == '0' ? '</span>' : '';
414
415
                // Id
416
                if ($this->teacherView) {
417
                    if ($this->exportToPdf == false) {
418
                        $row[] = $this->build_id_column($item);
419
                    }
420
                }
421
422
                // Type.
423
                $row[] = $this->build_type_column($item);
424
425
                // Name.
426
                if (get_class($item) === 'Category') {
427
                    $row[] = $invisibility_span_open.'<strong>'.$item->get_name().'</strong>'.$invisibility_span_close;
428
                    $main_categories[$item->get_id()]['name'] = $item->get_name();
429
                } else {
430
                    $name = $this->build_name_link($item, $type);
431
                    $row[] = $invisibility_span_open.$name.$invisibility_span_close;
432
                    $main_categories[$item->get_id()]['name'] = $name;
433
                }
434
435
                $this->dataForGraph['categories'][] = $item->get_name();
436
                $main_categories[$item->get_id()]['weight'] = $item->get_weight();
437
                $total_categories_weight += $item->get_weight();
438
439
                // Description.
440
                if ($this->exportToPdf == false) {
441
                    $row[] = $invisibility_span_open.$data[2].$invisibility_span_close;
442
                }
443
444
                // Weight.
445
                $weight = $scoredisplay->display_score(
446
                    [
447
                        $data['3'],
448
                        $this->currentcat->get_weight(),
449
                    ],
450
                    SCORE_SIMPLE,
451
                    SCORE_BOTH,
452
                    true
453
                );
454
455
                if ($this->teacherView) {
456
                    $row[] = $invisibility_span_open.
457
                        Display::tag('p', $weight, ['class' => 'score']).
458
                        $invisibility_span_close;
459
                } else {
460
                    $row[] = $invisibility_span_open.$weight.$invisibility_span_close;
461
                }
462
463
                $category_weight = $item->get_weight();
464
                $mainCategoryWeight = $main_cat[0]->get_weight();
465
466
                if ($this->teacherView) {
467
                    $weight_total_links += $data[3];
468
                } else {
469
                    $cattotal = Category::load($_GET['selectcat']);
470
                    $scoretotal = $cattotal[0]->calc_score($this->userId);
471
                }
472
473
                // Edit (for admins).
474
                if ($this->teacherView) {
475
                    $cat = new Category();
476
                    $show_message = $cat->show_message_resource_delete($item->get_course_code());
477
                    if ($show_message === false) {
478
                        $row[] = $this->build_edit_column($item);
479
                    }
480
                } else {
481
                    $score = $item->calc_score($this->userId);
482
                    $scoreToDisplay = '-';
483
                    if (!empty($score[1])) {
484
                        $completeScore = $scoredisplay->display_score($score, SCORE_DIV_PERCENT);
485
                        $score = $score[0] / $score[1] * $item->get_weight();
486
                        $score = $scoredisplay->display_score([$score, null], SCORE_SIMPLE);
487
                        $scoreToDisplay = Display::tip($score, $completeScore);
488
                    } else {
489
                        $categoryScore = null;
490
                    }
491
492
                    // Students get the results and certificates columns
493
494
                    $value_data = isset($data[4]) ? $data[4] : null;
495
                    $best = isset($data['best']) ? $data['best'] : null;
496
                    $average = isset($data['average']) ? $data['average'] : null;
497
                    $ranking = isset($data['ranking']) ? $data['ranking'] : null;
498
499
                    $totalResult = [
500
                        $data['result_score'][0],
501
                        $data['result_score'][1],
502
                    ];
503
504
                    $totalUserResult[0] += $totalResult[0] / ($totalResult[1] ?: 1) * $data[3];
505
                    $totalUserResult[1] += $data[3];
506
507
                    $totalBest = [
508
                        $scoredisplay->format_score($totalBest[0] + $data['best_score'][0]),
509
                        $scoredisplay->format_score($totalBest[1] + $data['best_score'][1]),
510
                    ];
511
512
                    $totalAverage = [
513
                        $data['average_score'][0],
514
                        $data['average_score'][1],
515
                    ];
516
517
                    // Student result
518
                    if (empty($model)) {
519
                        $row[] = $value_data;
520
                    } else {
521
                        $row[] = ExerciseLib::show_score(
522
                            $data['result_score'][0],
523
                            $data['result_score'][1]
524
                        );
525
                    }
526
527
                    $mode = SCORE_AVERAGE;
528
                    if ($userExerciseScoreInCategory) {
529
                        $mode = SCORE_SIMPLE;
530
531
                        $result = ExerciseLib::convertScoreToPlatformSetting($totalAverage[0], $totalAverage[1]);
532
                        $totalAverage[0] = $result['score'];
533
                        $totalAverage[1] = $result['weight'];
534
535
                        $result = ExerciseLib::convertScoreToPlatformSetting($totalResult[0], $totalResult[1]);
536
                        $totalResult[0] = $result['score'];
537
                        $totalResult[1] = $result['weight'];
538
539
                        $result = ExerciseLib::convertScoreToPlatformSetting(
540
                            $data['result_score'][0],
541
                            $data['result_score'][1]
542
                        );
543
                        $data['my_result_no_float'][0] = $result['score'];
544
                    }
545
546
                    $totalResultAverageValue = strip_tags($scoredisplay->display_score($totalResult, $mode));
547
                    $totalAverageValue = strip_tags($scoredisplay->display_score($totalAverage, $mode));
548
549
                    $this->dataForGraph['my_result'][] = floatval($totalResultAverageValue);
550
                    $this->dataForGraph['average'][] = floatval($totalAverageValue);
551
                    $this->dataForGraph['my_result_no_float'][] = $data['result_score'][0];
552
553
                    if (empty($model)) {
554
                        // Ranking
555
                        if (in_array(1, $this->loadStats)) {
556
                            $row[] = $ranking;
557
                        }
558
559
                        // Best
560
                        if (in_array(2, $this->loadStats)) {
561
                            $row[] = $best;
562
                        }
563
564
                        // Average
565
                        if (in_array(3, $this->loadStats)) {
566
                            $row[] = $average;
567
                        }
568
                    }
569
570
                    if (get_class($item) === 'Category') {
571
                        if ($this->exportToPdf == false) {
572
                            $row[] = $this->build_edit_column($item);
573
                        }
574
                    }
575
                }
576
577
                // Category added.
578
                $sortable_data[] = $row;
579
580
                // Loading children
581
                if (get_class($item) === 'Category') {
582
                    $parent_id = $item->get_id();
583
584
                    $cats = Category::load(
585
                        $parent_id,
586
                        null,
587
                        null,
588
                        null,
589
                        null,
590
                        null
591
                    );
592
593
                    if (isset($cats[0])) {
594
                        /** @var Category $subCategory */
595
                        $subCategory = $cats[0];
596
                        $allcat = $subCategory->get_subcategories($this->userId, $course_code, $session_id);
597
                        $alleval = $subCategory->get_evaluations($this->userId);
598
                        $alllink = $subCategory->get_links($this->userId);
599
600
                        $sub_cat_info = new GradebookDataGenerator($allcat, $alleval, $alllink);
601
                        $sub_cat_info->preLoadDataKey = $this->getPreloadDataKey();
602
                        $sub_cat_info->userId = $user_id;
603
                        $data_array2 = $sub_cat_info->get_data(
604
                            $sorting,
605
                            $from,
606
                            $this->per_page,
607
                            false,
608
                            $this->studentList
609
                        );
610
                        $total_weight = 0;
611
612
                        // Links.
613
                        foreach ($data_array2 as $data) {
614
                            $row = [];
615
                            $item = $data[0];
616
617
                            //if the item is invisible, wrap it in a span with class invisible
618
                            $invisibility_span_open = $isAllowedToEdit && $item->is_visible() == '0' ? '<span class="text-muted">' : '';
619
                            $invisibility_span_close = $isAllowedToEdit && $item->is_visible() == '0' ? '</span>' : '';
620
621
                            if (isset($item)) {
622
                                $main_categories[$parent_id]['children'][$item->get_id()]['name'] = $item->get_name();
623
                                $main_categories[$parent_id]['children'][$item->get_id()]['weight'] = $item->get_weight();
624
                            }
625
626
                            if ($this->teacherView) {
627
                                if ($this->exportToPdf == false) {
628
                                    $row[] = $this->build_id_column($item);
629
                                }
630
                            }
631
632
                            // Type
633
                            $row[] = $this->build_type_column($item, ['style' => 'padding-left:5px']);
634
635
                            // Name.
636
                            $row[] = $invisibility_span_open.'&nbsp;&nbsp;&nbsp; '.
637
                                $this->build_name_link($item, $type).$invisibility_span_close;
638
639
                            // Description.
640
                            if ($this->exportToPdf == false) {
641
                                $row[] = $invisibility_span_open.$data[2].$invisibility_span_close;
642
                            }
643
644
                            $weight = $data[3];
645
                            $total_weight += $weight;
646
647
                            // Weight
648
                            $row[] = $invisibility_span_open.$weight.$invisibility_span_close;
649
650
                            if ($this->teacherView) {
651
                                //$weight_total_links += intval($data[3]);
652
                            } else {
653
                                $cattotal = Category::load($_GET['selectcat']);
654
                                $scoretotal = $cattotal[0]->calc_score($this->userId);
655
                            }
656
657
                            // Admins get an edit column.
658
                            if (api_is_allowed_to_edit(null, true) &&
659
                                isset($_GET['user_id']) == false &&
660
                                (isset($_GET['action']) && $_GET['action'] != 'export_all' || !isset($_GET['action']))
661
                            ) {
662
                                $cat = new Category();
663
                                $show_message = $cat->show_message_resource_delete($item->get_course_code());
664
                                if ($show_message === false) {
665
                                    if ($this->exportToPdf == false) {
666
                                        $row[] = $this->build_edit_column($item);
667
                                    }
668
                                }
669
                            } else {
670
                                // Students get the results and certificates columns
671
                                $eval_n_links = array_merge($alleval, $alllink);
672
673
                                if (count($eval_n_links) > 0) {
674
                                    $value_data = isset($data[4]) ? $data[4] : null;
675
                                    if (!is_null($value_data)) {
676
                                        // Result
677
                                        $row[] = $value_data;
678
679
                                        $best = isset($data['best']) ? $data['best'] : null;
680
                                        $average = isset($data['average']) ? $data['average'] : null;
681
                                        $ranking = isset($data['ranking']) ? $data['ranking'] : null;
682
683
                                        if (in_array(1, $this->loadStats)) {
684
                                            // Ranking
685
                                            $row[] = $ranking;
686
                                        }
687
688
                                        if (in_array(2, $this->loadStats)) {
689
                                            // Best
690
                                            $row[] = $best;
691
                                        }
692
693
                                        // Average
694
                                        if (in_array(3, $this->loadStats)) {
695
                                            $row[] = $average;
696
                                        }
697
                                    }
698
                                }
699
700
                                if (!empty($cats)) {
701
                                    if ($this->exportToPdf == false) {
702
                                        $row[] = null;
703
                                    }
704
                                }
705
                            }
706
707
                            if ($this->exportToPdf == false) {
708
                                $row['child_of'] = $parent_id;
709
                            }
710
                            $sortable_data[] = $row;
711
                        }
712
713
                        // "Warning row"
714
                        if (!empty($data_array)) {
715
                            if ($this->teacherView) {
716
                                // Compare the category weight to the sum of all weights inside the category
717
                                if (intval($total_weight) == $category_weight) {
718
                                    $label = null;
719
                                    $total = GradebookUtils::score_badges(
720
                                        [
721
                                            $total_weight.' / '.$category_weight,
722
                                            '100',
723
                                        ]
724
                                    );
725
                                } else {
726
                                    $label = Display::return_icon(
727
                                        'warning.png',
728
                                        sprintf(get_lang('TotalWeightMustBeX'), $category_weight)
729
                                    );
730
                                    $total = Display::badge($total_weight.' / '.$category_weight, 'warning');
731
                                }
732
                                $row = [
733
                                    null,
734
                                    null,
735
                                    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>".get_lang('SubTotal').'</h5>',
736
                                    null,
737
                                    $total.' '.$label,
738
                                    'child_of' => $parent_id,
739
                                ];
740
                                $sortable_data[] = $row;
741
                            }
742
                        }
743
                    }
744
                }
745
            }
746
        } //end looping categories
747
748
        $main_weight = 0;
749
        if (count($main_cat) > 1) {
750
            /** @var Category $myCat */
751
            foreach ($main_cat as $myCat) {
752
                $myParentId = $myCat->get_parent_id();
753
                if ($myParentId == 0) {
754
                    $main_weight = (int) $myCat->get_weight();
755
                }
756
            }
757
        }
758
759
        if ($this->teacherView) {
760
            // Total for teacher.
761
            if (count($main_cat) > 1) {
762
                if (intval($total_categories_weight) == $main_weight) {
763
                    $total = GradebookUtils::score_badges(
764
                        [
765
                            $total_categories_weight.' / '.$main_weight,
766
                            '100',
767
                        ]
768
                    );
769
                } else {
770
                    $total = Display::badge($total_categories_weight.' / '.$main_weight, 'warning');
771
                }
772
                $row = [
773
                    null,
774
                    null,
775
                    '<strong>'.get_lang('Total').'</strong>',
776
                    null,
777
                    $total,
778
                ];
779
                $sortable_data[] = $row;
780
            }
781
        } else {
782
            // Total for student.
783
            if (count($main_cat) > 1) {
784
                $main_weight = (int) $main_cat[0]->get_weight();
785
                $global = null;
786
                $average = null;
787
                $myTotal = 0;
788
                foreach ($this->dataForGraph['my_result_no_float'] as $result) {
789
                    $myTotal += $result;
790
                }
791
792
                $totalResult[0] = $myTotal;
793
                // Overwrite main weight
794
                $totalResult[1] = $main_weight;
795
796
                $totalResult = $scoredisplay->display_score(
797
                    $totalResult,
798
                    SCORE_DIV
799
                );
800
801
                $row = [
802
                    null,
803
                    '<strong>'.get_lang('Total').'</strong>',
804
                ];
805
806
                if (!$this->exportToPdf) {
807
                    $row[] = null;
808
                }
809
810
                $row[] = $main_weight;
811
                $row[] = $totalResult;
812
                $categoryId = $main_cat[0]->get_id();
813
814
                if (in_array(1, $this->loadStats)) {
815
                    if (isset($defaultData[$categoryId]) && isset($defaultData[$categoryId]['ranking'])) {
816
                        $totalRanking = $defaultData[$categoryId]['ranking'];
817
                        $invalidateRanking = $defaultData[$categoryId]['ranking_invalidate'];
818
                    } else {
819
                        $totalRanking = [];
820
                        $invalidateRanking = true;
821
                        $average = 0;
822
                        $main_cat[0]->setStudentList($this->studentList);
823
                        foreach ($this->studentList as $student) {
824
                            $score = $main_cat[0]->calc_score(
825
                                $student['user_id'],
826
                                null,
827
                                api_get_course_id(),
828
                                api_get_session_id()
829
                            );
830
                            if (!empty($score[0])) {
831
                                $invalidateRanking = false;
832
                            }
833
                            $totalRanking[$student['user_id']] = $score[0];
834
                            $average += $score[0];
835
                        }
836
                        $defaultData[$categoryId]['ranking'] = $totalRanking;
837
                        $defaultData[$categoryId]['ranking_invalidate'] = $invalidateRanking;
838
                        Session::write($this->getPreloadDataKey(), $defaultData);
839
                    }
840
841
                    $totalRanking = AbstractLink::getCurrentUserRanking($user_id, $totalRanking);
842
                    $totalRanking = $scoredisplay->display_score(
843
                        $totalRanking,
844
                        SCORE_DIV,
845
                        SCORE_BOTH,
846
                        true,
847
                        true
848
                    );
849
850
                    if ($invalidateRanking) {
851
                        $totalRanking = null;
852
                    }
853
                    $row[] = $totalRanking;
854
                }
855
856
                if (in_array(2, $this->loadStats)) {
857
                    if (isset($defaultData[$categoryId]) && isset($defaultData[$categoryId]['best'])) {
858
                        $totalBest = $defaultData[$categoryId]['best'];
859
                    } else {
860
                        // Overwrite main weight
861
                        $totalBest[1] = $main_weight;
862
                        $defaultData[$categoryId]['best'] = $totalBest;
863
                    }
864
                    $totalBest = $scoredisplay->display_score(
865
                        $totalBest,
866
                        SCORE_DIV,
867
                        SCORE_BOTH,
868
                        true
869
                    );
870
                    $row[] = $totalBest;
871
                }
872
873
                if (in_array(3, $this->loadStats)) {
874
                    if (isset($defaultData[$categoryId]) && isset($defaultData[$categoryId]['average'])) {
875
                        $totalAverage = $defaultData[$categoryId]['average'];
876
                    } else {
877
                        // Overwrite main weight
878
                        $totalAverage[0] = $average / count($this->studentList);
879
                        $totalAverage[1] = $main_weight;
880
                        $defaultData[$categoryId]['average'] = $totalBest;
881
                    }
882
883
                    $totalAverage = $scoredisplay->display_score(
884
                        $totalAverage,
885
                        SCORE_DIV,
886
                        SCORE_BOTH,
887
                        true
888
                    );
889
890
                    $row[] = $totalAverage;
891
                }
892
893
                if (!empty($row)) {
894
                    $sortable_data[] = $row;
895
                }
896
            }
897
        }
898
899
        Session::write('default_data', $defaultData);
900
901
        // Warning messages
902
        $view = isset($_GET['view']) ? $_GET['view'] : null;
903
        if ($this->teacherView) {
904
            if (isset($_GET['selectcat']) &&
905
                $_GET['selectcat'] > 0 &&
906
                $view != 'presence'
907
            ) {
908
                $id_cat = (int) $_GET['selectcat'];
909
                $category = Category::load($id_cat);
910
                $weight_category = (int) $this->build_weight($category[0]);
911
                $course_code = $this->build_course_code($category[0]);
912
                $weight_total_links = round($weight_total_links);
913
914
                if ($weight_total_links > $weight_category ||
915
                    $weight_total_links < $weight_category ||
916
                    $weight_total_links > $weight_category
917
                ) {
918
                    $warning_message = sprintf(get_lang('TotalWeightMustBeX'), $weight_category);
919
                    $modify_icons =
920
                        '<a href="gradebook_edit_cat.php?editcat='.$id_cat.'&cidReq='.$course_code.'&id_session='.api_get_session_id().'">'.
921
                        Display::return_icon('edit.png', $warning_message, [], ICON_SIZE_SMALL).'</a>';
922
                    $warning_message .= $modify_icons;
923
                    echo Display::return_message($warning_message, 'warning', false);
924
                }
925
926
                $content_html = DocumentManager::replace_user_info_into_html(
927
                    api_get_user_id(),
928
                    api_get_course_info($course_code),
929
                    api_get_session_id()
930
                );
931
932
                if (!empty($content_html)) {
933
                    $new_content = explode('</head>', $content_html['content']);
934
                }
935
936
                if (empty($new_content[0])) {
937
                    // Set default certificate
938
                    $courseData = api_get_course_info($course_code);
939
                    DocumentManager::generateDefaultCertificate($courseData);
940
                }
941
            }
942
943
            if (empty($_GET['selectcat'])) {
944
                $categories = Category::load();
945
                $weight_categories = $certificate_min_scores = $course_codes = [];
946
                foreach ($categories as $category) {
947
                    $course_code_category = $this->build_course_code($category);
948
                    if (!empty($course_code)) {
949
                        if ($course_code_category == $course_code) {
950
                            $weight_categories[] = intval($this->build_weight($category));
951
                            $certificate_min_scores[] = intval($this->build_certificate_min_score($category));
952
                            $course_codes[] = $course_code;
953
                            break;
954
                        }
955
                    } else {
956
                        $weight_categories[] = intval($this->build_weight($category));
957
                        $certificate_min_scores[] = intval($this->build_certificate_min_score($category));
958
                        $course_codes[] = $course_code_category;
959
                    }
960
                }
961
962
                if (is_array($weight_categories) &&
963
                    is_array($certificate_min_scores) &&
964
                    is_array($course_codes)
965
                ) {
966
                    $warning_message = '';
967
                    for ($x = 0; $x < count($weight_categories); $x++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
968
                        $weight_category = intval($weight_categories[$x]);
969
                        $certificate_min_score = intval($certificate_min_scores[$x]);
970
                        $course_code = $course_codes[$x];
971
972
                        if (empty($certificate_min_score) ||
973
                            ($certificate_min_score > $weight_category)
974
                        ) {
975
                            $warning_message .= $course_code.
976
                                '&nbsp;-&nbsp;'.get_lang('CertificateMinimunScoreIsRequiredAndMustNotBeMoreThan').
977
                                '&nbsp;'.$weight_category.'<br />';
978
                        }
979
                    }
980
981
                    if (!empty($warning_message)) {
982
                        echo Display::return_message($warning_message, 'warning', false);
983
                    }
984
                }
985
            }
986
        }
987
988
        return $sortable_data;
989
    }
990
991
    /**
992
     * @return string
993
     */
994
    public function getGraph()
995
    {
996
        $data = $this->getDataForGraph();
997
        if (!empty($data) &&
998
            isset($data['categories']) &&
999
            isset($data['my_result']) &&
1000
            isset($data['average'])
1001
        ) {
1002
            $dataSet = new pData();
1003
            $dataSet->addPoints($data['my_result'], get_lang('Me'));
1004
            // In order to generate random values
1005
            // $data['average'] = array(rand(0,50), rand(0,50));
1006
            $dataSet->addPoints($data['average'], get_lang('Average'));
1007
            $dataSet->addPoints($data['categories'], 'categories');
1008
            $dataSet->setAbscissa('categories');
1009
            $xSize = 600;
1010
            $ySize = 400;
1011
            $pChart = new pImage($xSize, $ySize, $dataSet);
1012
            /* Turn of Antialiasing */
1013
            $pChart->Antialias = false;
1014
1015
            /* Add a border to the picture */
1016
            $pChart->drawRectangle(
1017
                0,
1018
                0,
1019
                $xSize - 1,
1020
                $ySize - 1,
1021
                ["R" => 0, "G" => 0, "B" => 0]
1022
            );
1023
            $pChart->drawText(
1024
                80,
1025
                16,
1026
                get_lang('Results'),
1027
                ["FontSize" => 11, "Align" => TEXT_ALIGN_BOTTOMMIDDLE]
1028
            );
1029
            $pChart->setGraphArea(50, 30, $xSize - 50, $ySize - 70);
1030
            $pChart->setFontProperties(
1031
                [
1032
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
1033
                    'FontSize' => 10,
1034
                ]
1035
            );
1036
1037
            /* Draw the scale */
1038
            $scaleSettings = [
1039
                "XMargin" => AUTO,
1040
                "YMargin" => 10,
1041
                "Floating" => true,
1042
                "GridR" => 200,
1043
                "GridG" => 200,
1044
                "GridB" => 200,
1045
                "DrawSubTicks" => true,
1046
                "CycleBackground" => true,
1047
                'LabelRotation' => 10,
1048
            ];
1049
            $pChart->drawScale($scaleSettings);
1050
1051
            /* Draw the line chart */
1052
            $pChart->drawLineChart();
1053
            $pChart->drawPlotChart(
1054
                [
1055
                    "DisplayValues" => true,
1056
                    "PlotBorder" => true,
1057
                    "BorderSize" => 2,
1058
                    "Surrounding" => -60,
1059
                    "BorderAlpha" => 80,
1060
                ]
1061
            );
1062
1063
            /* Write the chart legend */
1064
            $pChart->drawLegend(
1065
                $xSize - 180,
1066
                9,
1067
                [
1068
                    "Style" => LEGEND_NOBORDER,
1069
                    "Mode" => LEGEND_HORIZONTAL,
1070
                    "FontR" => 0,
1071
                    "FontG" => 0,
1072
                    "FontB" => 0,
1073
                ]
1074
            );
1075
1076
            $cachePath = api_get_path(SYS_ARCHIVE_PATH);
1077
            $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
1078
            $chartHash = $myCache->getHash($dataSet);
1079
1080
            $myCache->writeToCache($chartHash, $pChart);
1081
            $imgSysPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
1082
            $myCache->saveFromCache($chartHash, $imgSysPath);
1083
            $imgWebPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
1084
1085
            if (file_exists($imgSysPath)) {
1086
                $result = '<br /><div id="contentArea" style="text-align: center;" >';
1087
                $result .= '<img src="'.$imgWebPath.'" >';
1088
                $result .= '</div>';
1089
1090
                return $result;
1091
            }
1092
        }
1093
1094
        return '';
1095
    }
1096
1097
    /**
1098
     * @return array
1099
     */
1100
    private function getDataForGraph()
1101
    {
1102
        return $this->dataForGraph;
1103
    }
1104
1105
    /**
1106
     * @param $item
1107
     *
1108
     * @return mixed
1109
     */
1110
    private function build_certificate_min_score($item)
1111
    {
1112
        return $item->getCertificateMinScore();
1113
    }
1114
1115
    /**
1116
     * @param $item
1117
     *
1118
     * @return mixed
1119
     */
1120
    private function build_weight($item)
1121
    {
1122
        return $item->get_weight();
1123
    }
1124
1125
    /**
1126
     * @param $item
1127
     *
1128
     * @return mixed
1129
     */
1130
    private function build_course_code($item)
1131
    {
1132
        return $item->get_course_code();
1133
    }
1134
1135
    /**
1136
     * @param $item
1137
     *
1138
     * @return string
1139
     */
1140
    private function build_id_column($item)
1141
    {
1142
        switch ($item->get_item_type()) {
1143
            // category
1144
            case 'C':
1145
                return 'CATE'.$item->get_id();
1146
            // evaluation
1147
            case 'E':
1148
                return 'EVAL'.$item->get_id();
1149
            // link
1150
            case 'L':
1151
                return 'LINK'.$item->get_id();
1152
        }
1153
    }
1154
1155
    /**
1156
     * @param $item
1157
     * @param array $attributes
1158
     *
1159
     * @return string
1160
     */
1161
    private function build_type_column($item, $attributes = [])
1162
    {
1163
        return GradebookUtils::build_type_icon_tag($item->get_icon_name(), $attributes);
1164
    }
1165
1166
    /**
1167
     * Generate name column.
1168
     *
1169
     * @param GradebookItem $item
1170
     * @param string        $type simple|detail
1171
     *
1172
     * @return string
1173
     */
1174
    private function build_name_link($item, $type = 'detail')
1175
    {
1176
        $view = isset($_GET['view']) ? Security::remove_XSS($_GET['view']) : null;
1177
        $categoryId = $item->getCategory()->get_id();
1178
1179
        switch ($item->get_item_type()) {
1180
            // category
1181
            case 'C':
1182
                $prms_uri = '?selectcat='.$item->get_id().'&view='.$view;
1183
                $isStudentView = api_is_student_view_active();
1184
                if (isset($is_student) || $isStudentView) {
1185
                    $prms_uri = $prms_uri.'&amp;isStudentView=studentview';
1186
                }
1187
                $cat = new Category();
1188
                $show_message = $cat->show_message_resource_delete($item->get_course_code());
1189
1190
                return '&nbsp;<a href="'.Category::getUrl().$prms_uri.'">'
1191
                    .$item->get_name()
1192
                    .'</a>'
1193
                    .($item->is_course() ? ' &nbsp;['.$item->get_course_code().']'.$show_message : '');
1194
                // evaluation
1195
            case 'E':
1196
                $cat = new Category();
1197
                $course_id = CourseManager::get_course_by_category($categoryId);
1198
                $show_message = $cat->show_message_resource_delete($course_id);
1199
1200
                // course/platform admin can go to the view_results page
1201
                if (api_is_allowed_to_edit() && $show_message === false) {
1202
                    if ($item->get_type() == 'presence') {
1203
                        return '&nbsp;'
1204
                            .'<a href="gradebook_view_result.php?cidReq='.$course_id.'&amp;selecteval='.$item->get_id().'">'
1205
                            .$item->get_name()
1206
                            .'</a>';
1207
                    } else {
1208
                        $extra = Display::label(get_lang('Evaluation'));
1209
                        if ($type == 'simple') {
1210
                            $extra = '';
1211
                        }
1212
1213
                        return '&nbsp;'
1214
                            .'<a href="gradebook_view_result.php?'.api_get_cidreq().'&selecteval='.$item->get_id().'">'
1215
                            .$item->get_name()
1216
                            .'</a>&nbsp;'.$extra;
1217
                    }
1218
                } elseif (ScoreDisplay::instance()->is_custom() && $show_message === false) {
1219
                    // students can go to the statistics page (if custom display enabled)
1220
                    return '&nbsp;'
1221
                        .'<a href="gradebook_statistics.php?'.api_get_cidreq().'&selecteval='.$item->get_id().'">'
1222
                        .$item->get_name()
1223
                        .'</a>';
1224
                } elseif ($show_message === false && !api_is_allowed_to_edit() && !ScoreDisplay::instance()->is_custom()) {
1225
                    return '&nbsp;'
1226
                        .'<a href="gradebook_statistics.php?'.api_get_cidreq().'&selecteval='.$item->get_id().'">'
1227
                        .$item->get_name()
1228
                        .'</a>';
1229
                } else {
1230
                    return '['.get_lang('Evaluation').']&nbsp;&nbsp;'.$item->get_name().$show_message;
1231
                }
1232
                // no break because of return
1233
            case 'L':
1234
                // link
1235
                $cat = new Category();
1236
                $course_id = CourseManager::get_course_by_category($categoryId);
1237
                $show_message = $cat->show_message_resource_delete($course_id);
1238
1239
                $url = $item->get_link();
1240
1241
                $text = $item->get_name();
1242
                if (isset($url) && $show_message === false) {
1243
                    $text = '&nbsp;<a href="'.$item->get_link().'">'
1244
                        .$item->get_name()
1245
                        .'</a>';
1246
                }
1247
1248
                $extra = Display::label($item->get_type_name(), 'info');
1249
                if ($type == 'simple') {
1250
                    $extra = '';
1251
                }
1252
                $extra .= $item->getSkillsFromItem();
1253
1254
                $text .= "&nbsp;".$extra.$show_message;
1255
                $cc = $this->currentcat->get_course_code();
1256
                if (empty($cc)) {
1257
                    $text .= '&nbsp;[<a href="'.api_get_path(REL_COURSE_PATH).$item->get_course_code().'/">'.$item->get_course_code().'</a>]';
1258
                }
1259
1260
                return $text;
1261
        }
1262
    }
1263
1264
    /**
1265
     * @param AbstractLink $item
1266
     *
1267
     * @return string|null
1268
     */
1269
    private function build_edit_column($item)
1270
    {
1271
        switch ($item->get_item_type()) {
1272
            // category
1273
            case 'C':
1274
                return GradebookUtils::build_edit_icons_cat($item, $this->currentcat);
1275
            // evaluation
1276
            case 'E':
1277
                return GradebookUtils::build_edit_icons_eval($item, $this->currentcat->get_id());
1278
            // link
1279
            case 'L':
1280
                return GradebookUtils::build_edit_icons_link($item, $this->currentcat->get_id());
1281
        }
1282
    }
1283
}
1284