Passed
Push — master ( 720cec...952861 )
by
unknown
16:43 queued 08:12
created

GradebookTable::safeScore()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 6
rs 10
c 1
b 0
f 0
1
<?php
2
3
/* For licensing terms, see license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ActionIcon;
6
use Chamilo\CoreBundle\Component\Utils\StateIcon;
7
use ChamiloSession as Session;
8
use CpChart\Cache as pCache;
9
use CpChart\Data as pData;
10
use CpChart\Image as pImage;
11
12
/**
13
 * GradebookTable Class
14
 * Table to display categories, evaluations and links.
15
 *
16
 * @author Stijn Konings
17
 * @author Bert Steppé (refactored, optimised)
18
 */
19
class GradebookTable extends SortableTable
20
{
21
    public $cats;
22
    public $exportToPdf;
23
    public $teacherView;
24
    public $userId;
25
    public $studentList = [];
26
    private $currentcat;
27
    private $datagen;
28
    private $evals_links;
29
    private $dataForGraph;
30
    /**
31
     * @var array Indicates which columns should be shown in gradebook
32
     *
33
     * @example [1] For add Ranking column
34
     *          [2] For add Best Score column
35
     *          [3] For add Average column
36
     */
37
    private $loadStats = [];
38
39
    /**
40
     * GradebookTable constructor.
41
     */
42
    public function __construct(
43
        Category $currentcat,
44
        array $cats = [],
45
        array $evals = [],
46
        array $links = [],
47
        array $addparams = [],
48
        bool $exportToPdf = false,
49
        ?bool $showTeacherView = null,
50
        ?int $userId = null,
51
        array $studentList = [],
52
        array $loadStats = []
53
    ) {
54
        $this->teacherView = is_null($showTeacherView) ? api_is_allowed_to_edit(null, true) : $showTeacherView;
55
        $this->userId = is_null($userId) ? api_get_user_id() : $userId;
56
        $this->exportToPdf = $exportToPdf;
57
        $this->studentList = $studentList;
58
59
        parent::__construct(
60
            'gradebooklist',
61
            null,
62
            null,
63
            api_is_allowed_to_edit() ? 1 : 0,
64
            1000,
65
            'ASC',
66
            'gradebook_list'
67
        );
68
69
        $this->evals_links = array_merge($evals, $links);
70
        $this->currentcat = $currentcat;
71
        $this->cats = $cats;
72
        $this->loadStats = $loadStats;
73
        $this->datagen = new GradebookDataGenerator($cats, $evals, $links);
74
        $this->datagen->exportToPdf = $this->exportToPdf;
75
        $this->datagen->preLoadDataKey = $this->getPreloadDataKey();
76
        $this->datagen->hidePercentage = ('true' === api_get_setting('gradebook.hide_gradebook_percentage_user_result'));
77
78
        if (!empty($userId)) {
79
            $this->datagen->userId = $userId;
80
        }
81
82
        if (!empty($addparams)) {
83
            $this->set_additional_parameters($addparams);
84
        }
85
86
        $column = 0;
87
        if ($this->teacherView) {
88
            if (false == $this->exportToPdf) {
89
                $this->set_header($column++, '', '', 'width="25px"');
90
            }
91
        }
92
93
        $this->set_header($column++, get_lang('Type'), '', 'width="20px"');
94
        $this->set_header($column++, get_lang('Name'), false);
95
        if (false == $this->exportToPdf) {
96
            $this->set_header($column++, get_lang('Description'), false);
97
        }
98
99
        $model = ExerciseLib::getCourseScoreModel();
100
        $settings = api_get_setting('gradebook.gradebook_pdf_export_settings', true);
101
        $showWeight = true;
102
        if ($this->exportToPdf && isset($settings['hide_score_weight']) && $settings['hide_score_weight']) {
103
            $showWeight = false;
104
        }
105
        if ($showWeight) {
106
            $this->set_header(
107
                $column++,
108
                get_lang('Weight'),
109
                '',
110
                'width="100px"'
111
            );
112
        }
113
114
        if (!$this->teacherView) {
115
            $this->set_header($column++, get_lang('Result'), false);
116
        }
117
118
        if (empty($model)) {
119
            if (in_array(1, $this->loadStats)) {
120
                $this->set_header($column++, get_lang('Ranking'), false, 'width="50px"');
121
            }
122
            if (in_array(2, $this->loadStats)) {
123
                $this->set_header($column++, get_lang('Best scoree'), false, 'width="140px"');
124
            }
125
            if (in_array(3, $this->loadStats)) {
126
                $this->set_header($column++, get_lang('Average'), false, 'width="140px"');
127
            }
128
        }
129
130
        if ($this->teacherView) {
131
        } else {
132
            if (!empty($cats)) {
133
                if (false == $this->exportToPdf) {
134
                    $this->set_header($column++, get_lang('Detail'), false);
135
                }
136
            }
137
        }
138
139
        // Deactivates the odd/even alt rows in order that the +/- buttons work see #4047
140
        $this->odd_even_rows_enabled = false;
141
142
        // Admins get an edit column.
143
        if ($this->teacherView) {
144
            $this->set_header($column++, get_lang('Edit'), false, 'width="195px"');
145
            // Detail on multiple selected documents.
146
            $this->set_form_actions(
147
                [
148
                    'setvisible' => get_lang('Set visible'),
149
                    'setinvisible' => get_lang('Set invisible'),
150
                    'deleted' => get_lang('Delete selected'),
151
                ]
152
            );
153
        } else {
154
            if (empty($_GET['selectcat']) && !$this->teacherView) {
155
                if (false == $this->exportToPdf) {
156
                    $this->set_header(
157
                        $column++,
158
                        get_lang('Certificates'),
159
                        false
160
                    );
161
                }
162
            }
163
        }
164
    }
165
166
    /**
167
     * @return GradebookDataGenerator
168
     */
169
    public function get_data()
170
    {
171
        return $this->datagen;
172
    }
173
174
    /**
175
     * Function used by SortableTable to get total number of items in the table.
176
     *
177
     * @return int
178
     */
179
    public function get_total_number_of_items()
180
    {
181
        return $this->datagen->get_total_items_count();
182
    }
183
184
    /**
185
     * @return string
186
     */
187
    public function getPreloadDataKey()
188
    {
189
        return 'default_data_'.api_get_course_id().'_'.api_get_session_id();
190
    }
191
192
    public function preloadData()
193
    {
194
        $allitems = $this->datagen->items;
195
        usort($allitems, ['GradebookDataGenerator', 'sort_by_name']);
196
        $visibleItems = array_merge($this->datagen->items, $this->evals_links);
197
        $defaultDataFromSession = Session::read($this->getPreloadDataKey());
198
        if (empty($defaultDataFromSession)) {
199
            $defaultData = [];
200
            /** @var GradebookItem $item */
201
            foreach ($visibleItems as $item) {
202
                $item->setStudentList($this->studentList);
203
                $itemType = get_class($item);
204
                switch ($itemType) {
205
                    case 'Evaluation':
206
                        // Best
207
                        $best = $this->datagen->buildBestResultColumn($item);
208
                        $defaultData[$item->get_id()]['best'] = $best;
209
                        // Average
210
                        $average = $this->datagen->buildAverageResultColumn($item);
211
                        $defaultData[$item->get_id()]['average'] = $average;
212
                        break;
213
                    case 'ExerciseLink':
214
                        /** @var ExerciseLink $item */
215
                        // Best
216
                        $best = $this->datagen->buildBestResultColumn($item);
217
                        $defaultData[$item->get_id()]['best'] = $best;
218
                        // Average
219
                        $average = $this->datagen->buildAverageResultColumn($item);
220
                        $defaultData[$item->get_id()]['average'] = $average;
221
                        // Ranking
222
                        /*if (!empty($this->studentList)) {
223
                            $invalidateRanking = true;
224
                            foreach ($this->studentList as $user) {
225
                                $score = $this->datagen->build_result_column(
226
                                    $user['user_id'],
227
                                    $item,
228
                                    false,
229
                                    true
230
                                );
231
                                if (!empty($score['score'])) {
232
                                    $invalidateRanking = false;
233
                                }
234
                                $rankingStudentList[$user['user_id']] = $score['score'][0];
235
                                $defaultData[$item->get_id()]['ranking'] = $rankingStudentList;
236
                                $defaultData[$item->get_id()]['ranking_invalidate'] = $invalidateRanking;
237
                            }
238
                        }*/
239
                        break;
240
                    default:
241
                        // Best
242
                        $best = $this->datagen->buildBestResultColumn($item);
243
                        $defaultData[$item->get_id()]['best'] = $best;
244
245
                        // Average
246
                        $average = $this->datagen->buildAverageResultColumn($item);
247
                        $defaultData[$item->get_id()]['average'] = $average;
248
249
                        // Ranking
250
                        if (!empty($this->studentList)) {
251
                            $invalidateRanking = true;
252
                            foreach ($this->studentList as $user) {
253
                                $score = $this->datagen->build_result_column(
254
                                    $user['user_id'],
255
                                    $item,
256
                                    false,
257
                                    true
258
                                );
259
                                if (!empty($score['score'])) {
260
                                    $invalidateRanking = false;
261
                                }
262
                                $rankingStudentList[$user['user_id']] = $score['score'][0];
263
                                $defaultData[$item->get_id()]['ranking'] = $rankingStudentList;
264
                                $defaultData[$item->get_id()]['ranking_invalidate'] = $invalidateRanking;
265
                            }
266
                        }
267
                        break;
268
                }
269
            }
270
            Session::write($this->getPreloadDataKey(), $defaultData);
271
        } else {
272
            $defaultData = $defaultDataFromSession;
273
        }
274
275
        return $defaultData;
276
    }
277
278
    private function safeScore(array $score = null): array
279
    {
280
        $score = $score ?? [];
281
        return [
282
            $score[0] ?? 0,
283
            $score[1] ?? 1
284
        ];
285
    }
286
287
    /**
288
     * Function used by SortableTable to generate the data to display.
289
     *
290
     * @param int    $from
291
     * @param int    $perPage
292
     * @param int    $column
293
     * @param string $direction
294
     * @param int    $sort
295
     *
296
     * @return array|mixed
297
     */
298
    public function get_table_data($from = 1, $perPage = null, $column = null, $direction = null, $sort = null)
299
    {
300
        //variables load in index.php
301
        global $certificate_min_score;
302
303
        $isAllowedToEdit = api_is_allowed_to_edit();
304
        // determine sorting type
305
        $col_adjust = $isAllowedToEdit ? 1 : 0;
306
        // By id
307
        $this->column = 5;
308
309
        switch ($this->column) {
310
            // Type
311
            case 0 + $col_adjust:
312
                $sorting = GradebookDataGenerator::GDG_SORT_TYPE;
313
                break;
314
            case 1 + $col_adjust:
315
                $sorting = GradebookDataGenerator::GDG_SORT_NAME;
316
                break;
317
            case 2 + $col_adjust:
318
                $sorting = GradebookDataGenerator::GDG_SORT_DESCRIPTION;
319
                break;
320
            case 3 + $col_adjust:
321
                $sorting = GradebookDataGenerator::GDG_SORT_WEIGHT;
322
                break;
323
            case 4 + $col_adjust:
324
                $sorting = GradebookDataGenerator::GDG_SORT_DATE;
325
                break;
326
            case 5 + $col_adjust:
327
                $sorting = GradebookDataGenerator::GDG_SORT_ID;
328
                break;
329
        }
330
331
        if ('DESC' == $this->direction) {
332
            $sorting |= GradebookDataGenerator::GDG_SORT_DESC;
333
        } else {
334
            $sorting |= GradebookDataGenerator::GDG_SORT_ASC;
335
        }
336
337
        // Status of user in course.
338
        $user_id = $this->userId;
339
        $course_code = api_get_course_id();
340
        $courseId = api_get_course_int_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::getUserListFromCourseId(
350
                $courseId,
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
            api_get_course_int_id(),
376
            null,
377
            null,
378
            $session_id,
379
            'ORDER BY id'
380
        );
381
382
        $totalCategoriesWeight = 0;
383
        $scoredisplay = ScoreDisplay::instance();
384
        $totalBest = [0, 0];
385
        $totalAverage = [0, 0];
386
387
        $type = 'detail';
388
        if ($this->exportToPdf) {
389
            $type = 'simple';
390
        }
391
392
        $model = ExerciseLib::getCourseScoreModel();
393
        $userExerciseScoreInCategory = ('true' === api_get_setting('gradebook.gradebook_use_exercise_score_settings_in_categories'));
394
        $useExerciseScoreInTotal = ('true' === api_get_setting('gradebook.gradebook_use_exercise_score_settings_in_total'));
395
        $course_code = api_get_course_id();
396
        $session_id = api_get_session_id();
397
        $defaultData = Session::read($this->getPreloadDataKey());
398
        $settings = api_get_setting('gradebook.gradebook_pdf_export_settings', true);
399
        $showWeight = true;
400
        if ($this->exportToPdf && isset($settings['hide_score_weight']) && $settings['hide_score_weight']) {
401
            $showWeight = false;
402
        }
403
        $totalAverageList = [];
404
        // Categories.
405
        if (!empty($data_array)) {
406
            foreach ($data_array as $data) {
407
                // list of items inside the gradebook (exercises, lps, forums, etc)
408
                $row = [];
409
                /** @var AbstractLink $item */
410
                $item = $data[0];
411
                // If the item is invisible, wrap it in a span with class invisible
412
                $invisibility_span_open = $isAllowedToEdit && '0' == $item->is_visible() ? '<span class="text-muted">' : '';
413
                $invisibility_span_close = $isAllowedToEdit && '0' == $item->is_visible() ? '</span>' : '';
414
415
                if ($this->teacherView) {
416
                    if (false == $this->exportToPdf) {
417
                        $row[] = $this->build_id_column($item);
418
                    }
419
                }
420
421
                // Type.
422
                $row[] = $this->build_type_column($item);
423
424
                // Name.
425
                if ('Category' === get_class($item)) {
426
                    $row[] = $invisibility_span_open.'<strong>'.$item->get_name().'</strong>'.$invisibility_span_close;
427
                    $main_categories[$item->get_id()]['name'] = $item->get_name();
428
                } else {
429
                    $name = $this->build_name_link($item, $type);
430
                    $row[] = $invisibility_span_open.$name.$invisibility_span_close;
431
                    $main_categories[$item->get_id()]['name'] = $name;
432
                }
433
434
                $this->dataForGraph['categories'][] = $item->get_name();
435
                $main_categories[$item->get_id()]['weight'] = $item->get_weight();
436
                $totalCategoriesWeight += $item->get_weight();
437
438
                // Description.
439
                if (false == $this->exportToPdf) {
440
                    $row[] = $invisibility_span_open.$data[2].$invisibility_span_close;
441
                }
442
443
                // Weight.
444
                $weight = $scoredisplay->display_score(
445
                    [
446
                        $data['3'],
447
                        $this->currentcat->get_weight(),
448
                    ],
449
                    SCORE_SIMPLE,
450
                    SCORE_BOTH,
451
                    true
452
                );
453
454
                if ($showWeight) {
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
464
                $categoryWeight = $item->get_weight();
465
                if ($this->teacherView) {
466
                    $weight_total_links += $data[3];
467
                }
468
469
                // Edit (for admins).
470
                if ($this->teacherView) {
471
                    $show_message = Category::show_message_resource_delete($item->getCourseId());
472
                    if (empty($show_message)) {
473
                        $row[] = $this->build_edit_column($item);
474
                    }
475
                } else {
476
                    // Students get the results and certificates columns
477
                    $value_data = isset($data[4]) ? $data[4] : null;
478
                    $best = isset($data['best']) ? $data['best'] : null;
479
                    $average = isset($data['average']) ? $data['average'] : null;
480
                    $ranking = isset($data['ranking']) ? $data['ranking'] : null;
481
                    $totalResult = [];
482
                    if (isset($data['result_score'])) {
483
                        $totalResult = [
484
                            $data['result_score'][0] ?? 0,
485
                            $data['result_score'][1] ?? 0,
486
                        ];
487
                    }
488
489
                    if (empty($model)) {
490
                        $data['best_score'][0] = $data['best_score'][0] ?? 0;
491
                        $data['best_score'][1] = $data['best_score'][1] ?? 0;
492
                        $totalBest = [
493
                            $scoredisplay->format_score($totalBest[0] + $data['best_score'][0]),
494
                            $scoredisplay->format_score($totalBest[1] + $data['best_score'][1]),
495
                        ];
496
                        $totalAverage = [0, 0];
497
                        if (isset($data['average_score']) && !empty($data['average_score'])) {
498
                            $totalAverage = [
499
                                $data['average_score'][0],
500
                                $data['average_score'][1],
501
                            ];
502
                        }
503
                    }
504
505
                    // Score
506
                    if (empty($model)) {
507
                        $row[] = $value_data;
508
                    } else {
509
                        $row[] = ExerciseLib::show_score(
510
                            $data['result_score'][0],
511
                            $data['result_score'][1]
512
                        );
513
                    }
514
515
                    $totalAverageList[$item->get_id()] = $totalAverage;
516
                    $mode = SCORE_AVERAGE;
517
                    if ($userExerciseScoreInCategory) {
518
                        $mode = SCORE_SIMPLE;
519
                        list($avgScore, $avgWeight) = $this->safeScore($totalAverage);
520
                        $result = ExerciseLib::convertScoreToPlatformSetting($avgScore, $avgWeight);
521
522
                        $totalAverage[0] = $result['score'];
523
                        $totalAverage[1] = $result['weight'];
524
525
                        list($resScore, $resWeight) = $this->safeScore($totalResult);
526
                        $result = ExerciseLib::convertScoreToPlatformSetting($resScore, $resWeight);
527
528
                        $totalResult[0] = $result['score'];
529
                        $totalResult[1] = $result['weight'];
530
531
                        list($safeScore, $safeWeight) = $this->safeScore($data['result_score'] ?? []);
532
                        $result = ExerciseLib::convertScoreToPlatformSetting($safeScore, $safeWeight);
533
534
                        $data['my_result_no_float'][0] = $result['score'];
535
                    }
536
537
                    $totalResultAverageValue = strip_tags(
538
                        $scoredisplay->display_score($totalResult, $mode, null, false, false, true)
539
                    );
540
                    $totalAverageValue = strip_tags(
541
                        $scoredisplay->display_score($totalAverage, $mode, null, false, false, true)
542
                    );
543
544
                    $this->dataForGraph['my_result'][] = floatval($totalResultAverageValue);
545
                    $this->dataForGraph['average'][] = floatval($totalAverageValue);
546
                    $this->dataForGraph['my_result_no_float'][] = $data['result_score'][0] ?? 0;
547
548
                    if (empty($model)) {
549
                        // Ranking
550
                        if (in_array(1, $this->loadStats)) {
551
                            $row[] = $ranking;
552
                        }
553
554
                        // Best
555
                        if (in_array(2, $this->loadStats)) {
556
                            $row[] = $best;
557
                        }
558
559
                        // Average
560
                        if (in_array(3, $this->loadStats)) {
561
                            $row[] = $average;
562
                        }
563
                    }
564
565
                    if ('Category' === get_class($item)) {
566
                        if (false == $this->exportToPdf) {
567
                            $row[] = $this->build_edit_column($item);
568
                        }
569
                    }
570
                }
571
572
                // Category added.
573
                $sortable_data[] = $row;
574
575
                // Loading children
576
                if ('Category' === get_class($item)) {
577
                    $parent_id = $item->get_id();
578
                    $cats = Category::load(
579
                        $parent_id,
580
                        null,
581
                        0,
582
                        null,
583
                        null,
584
                        null
585
                    );
586
587
                    if (isset($cats[0])) {
588
                        /** @var Category $subCategory */
589
                        $subCategory = $cats[0];
590
                        $allcat = $subCategory->get_subcategories($this->userId, $courseId, $session_id);
591
                        $alleval = $subCategory->get_evaluations($this->userId);
592
                        $alllink = $subCategory->get_links($this->userId);
593
594
                        $sub_cat_info = new GradebookDataGenerator($allcat, $alleval, $alllink);
595
                        $sub_cat_info->exportToPdf = $this->exportToPdf;
596
                        $sub_cat_info->preLoadDataKey = $this->getPreloadDataKey();
597
                        $sub_cat_info->userId = $user_id;
598
599
                        $data_array2 = $sub_cat_info->get_data(
600
                            $sorting,
601
                            $from,
602
                            $this->per_page,
603
                            false,
604
                            $this->studentList
605
                        );
606
                        $totalWeight = 0;
607
608
                        // Links.
609
                        foreach ($data_array2 as $data) {
610
                            $row = [];
611
                            $item = $data[0];
612
                            //if the item is invisible, wrap it in a span with class invisible
613
                            $invisibility_span_open = $isAllowedToEdit && '0' == $item->is_visible() ? '<span class="text-muted">' : '';
614
                            $invisibility_span_close = $isAllowedToEdit && '0' == $item->is_visible() ? '</span>' : '';
615
616
                            if (isset($item)) {
617
                                $main_categories[$parent_id]['children'][$item->get_id()]['name'] = $item->get_name();
618
                                $main_categories[$parent_id]['children'][$item->get_id()]['weight'] = $item->get_weight();
619
                            }
620
621
                            if ($this->teacherView) {
622
                                if (false == $this->exportToPdf) {
623
                                    $row[] = $this->build_id_column($item);
624
                                }
625
                            }
626
627
                            // Type
628
                            $row[] = $this->build_type_column($item, 'padding-left:5px');
629
                            // Name.
630
                            $row[] = $invisibility_span_open.'&nbsp;&nbsp;&nbsp; '.
631
                                $this->build_name_link($item, $type, 4).$invisibility_span_close;
632
633
                            // Description.
634
                            if (false == $this->exportToPdf) {
635
                                $row[] = $invisibility_span_open.$data[2].$invisibility_span_close;
636
                            }
637
638
                            $weight = $data[3];
639
                            $totalWeight += $weight;
640
641
                            // Weight
642
                            if ($showWeight) {
643
                                $row[] = $invisibility_span_open.$weight.$invisibility_span_close;
644
                            }
645
646
                            // Admins get an edit column.
647
                            if (api_is_allowed_to_edit(null, true) &&
648
                                false == isset($_GET['user_id']) &&
649
                                (isset($_GET['action']) && 'export_all' != $_GET['action'] || !isset($_GET['action']))
650
                            ) {
651
                                $show_message = Category::show_message_resource_delete($item->getCourseId());
652
                                if (empty($show_message)) {
653
                                    if (false == $this->exportToPdf) {
654
                                        $row[] = $this->build_edit_column($item);
655
                                    }
656
                                }
657
                            } else {
658
                                // Students get the results and certificates columns
659
                                $eval_n_links = array_merge($alleval, $alllink);
660
                                if (count($eval_n_links) > 0) {
661
                                    $value_data = isset($data[4]) ? $data[4] : null;
662
                                    if (!is_null($value_data)) {
663
                                        // Result
664
                                        $row[] = $value_data;
665
                                        $best = isset($data['best']) ? $data['best'] : null;
666
                                        $average = isset($data['average']) ? $data['average'] : null;
667
                                        $ranking = isset($data['ranking']) ? $data['ranking'] : null;
668
                                        if (empty($model)) {
669
                                            // Ranking
670
                                            if (in_array(1, $this->loadStats)) {
671
                                                $row[] = $ranking;
672
                                            }
673
674
                                            // Best
675
                                            if (in_array(2, $this->loadStats)) {
676
                                                $row[] = $best;
677
                                            }
678
679
                                            // Average
680
                                            if (in_array(3, $this->loadStats)) {
681
                                                $row[] = $average;
682
                                            }
683
                                        }
684
                                    }
685
                                }
686
687
                                if (!empty($cats)) {
688
                                    if (false == $this->exportToPdf) {
689
                                        $row[] = null;
690
                                    }
691
                                }
692
                            }
693
694
                            if (false == $this->exportToPdf) {
695
                                $row['child_of'] = $parent_id;
696
                            }
697
                            $sortable_data[] = $row;
698
                        }
699
700
                        // "Warning row"
701
                        if (!empty($data_array)) {
702
                            if ($this->teacherView) {
703
                                // Compare the category weight to the sum of all weights inside the category
704
                                if (intval($totalWeight) == $categoryWeight) {
705
                                    $label = null;
706
                                    $total = GradebookUtils::scoreBadges(
707
                                        [
708
                                            $totalWeight.' / '.$categoryWeight,
709
                                            '100',
710
                                        ]
711
                                    );
712
                                } else {
713
                                    $label = Display::getMdiIcon(
714
                                        StateIcon::WARNING,
715
                                        'ch-tool-icon',
716
                                        null,
717
                                        ICON_SIZE_SMALL,
718
                                        sprintf(get_lang('The sum of all weights of activities must be %s'), $categoryWeight)
719
                                    );
720
                                    $total = Display::label($totalWeight.' / '.$categoryWeight, 'warning');
721
                                }
722
                                $row = [
723
                                    null,
724
                                    null,
725
                                    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>".get_lang('Subtotal').'</h5>',
726
                                    null,
727
                                    $total.' '.$label,
728
                                    'child_of' => $parent_id,
729
                                ];
730
                                $sortable_data[] = $row;
731
                            }
732
                        }
733
                    }
734
                }
735
            }
736
        } //end looping categories
737
738
        $mainWeight = 0;
739
        if (count($main_cat) > 1) {
740
            /** @var Category $myCat */
741
            foreach ($main_cat as $myCat) {
742
                $myParentId = $myCat->get_parent_id();
743
                if (0 == $myParentId) {
744
                    $mainWeight = (int) $myCat->get_weight();
745
                }
746
            }
747
        }
748
749
        if ($this->teacherView) {
750
            // Total for teacher.
751
            if (count($main_cat) > 1) {
752
                if (intval($totalCategoriesWeight) == $mainWeight) {
753
                    $total = GradebookUtils::scoreBadges(
754
                        [
755
                            $totalCategoriesWeight.' / '.$mainWeight,
756
                            '100',
757
                        ]
758
                    );
759
                } else {
760
                    $total = Display::label($totalCategoriesWeight.' / '.$mainWeight, 'warning');
761
                }
762
                $row = [
763
                    null,
764
                    null,
765
                    '<strong>'.get_lang('Total').'</strong>',
766
                    null,
767
                    $total,
768
                ];
769
                $sortable_data[] = $row;
770
            }
771
        } else {
772
            $showPercentage = false === $this->datagen->hidePercentage;
773
            // Total for student.
774
            if (count($main_cat) > 1) {
775
                $mainWeight = (int) $main_cat[0]->get_weight();
776
                $global = null;
777
                $average = null;
778
                $myTotal = 0;
779
780
                if (isset($this->dataForGraph['my_result_no_float'])) {
781
                    foreach ($this->dataForGraph['my_result_no_float'] as $result) {
782
                        $myTotal += $result;
783
                    }
784
                }
785
786
                $totalResult[0] = $myTotal;
787
                // Overwrite main weight
788
                $totalResult[1] = $mainWeight;
789
790
                if (!empty($model)) {
791
                    $totalResult = ExerciseLib::show_score($totalResult[0], $totalResult[1], false);
792
                } else {
793
                    $totalResult = $scoredisplay->display_score(
794
                        $totalResult,
795
                        SCORE_DIV,
796
                        null,
797
                        false,
798
                        false,
799
                        true
800
                    );
801
802
                    if ($useExerciseScoreInTotal) {
803
                        $totalResult = ExerciseLib::show_score($myTotal, $mainWeight, false);
804
                    }
805
                }
806
807
                $row = [
808
                    null,
809
                    '<strong>'.get_lang('Total').'</strong>',
810
                ];
811
812
                if (!$this->exportToPdf) {
813
                    $row[] = null;
814
                }
815
816
                if ($showWeight) {
817
                    $row[] = $mainWeight;
818
                }
819
820
                $row[] = $totalResult;
821
                $categoryId = $main_cat[0]->get_id();
822
823
                if (empty($model)) {
824
                    if (in_array(1, $this->loadStats)) {
825
                        if (isset($defaultData[$categoryId]) && isset($defaultData[$categoryId]['ranking'])) {
826
                            $totalRanking = $defaultData[$categoryId]['ranking'];
827
                            $invalidateRanking = $defaultData[$categoryId]['ranking_invalidate'];
828
                            $average = 0;
829
                            foreach ($totalRanking as $ranking) {
830
                                $average += $ranking;
831
                            }
832
                        } else {
833
                            $totalRanking = [];
834
                            $invalidateRanking = true;
835
                            $average = 0;
836
                            $main_cat[0]->setStudentList($this->studentList);
837
                            foreach ($this->studentList as $student) {
838
                                $score = $main_cat[0]->calc_score(
839
                                    $student['user_id'],
840
                                    null,
841
                                    $courseId,
842
                                    $session_id
843
                                );
844
                                if (!empty($score[0])) {
845
                                    $invalidateRanking = false;
846
                                }
847
                                $totalRanking[$student['user_id']] = $score[0];
848
                                $average += $score[0];
849
                            }
850
                            $defaultData[$categoryId]['ranking'] = $totalRanking;
851
                            $defaultData[$categoryId]['ranking_invalidate'] = $invalidateRanking;
852
                            Session::write($this->getPreloadDataKey(), $defaultData);
853
                        }
854
855
                        $totalRanking = AbstractLink::getCurrentUserRanking($user_id, $totalRanking);
856
                        $totalRanking = $scoredisplay->display_score(
857
                            $totalRanking,
858
                            SCORE_DIV,
859
                            SCORE_BOTH,
860
                            true,
861
                            true,
862
                            true
863
                        );
864
865
                        if ($invalidateRanking) {
866
                            $totalRanking = null;
867
                        }
868
                        $row[] = $totalRanking;
869
                    }
870
871
                    if (in_array(2, $this->loadStats)) {
872
                        if (isset($defaultData[$categoryId]) && isset($defaultData[$categoryId]['best'])) {
873
                            $totalBest = $defaultData[$categoryId]['best'];
874
                        } else {
875
                            // Overwrite main weight
876
                            $totalBest[1] = $mainWeight;
877
                            $defaultData[$categoryId]['best'] = $totalBest;
878
                        }
879
880
                        if ($useExerciseScoreInTotal) {
881
                            if (isset($totalBest['score'])) {
882
                                $totalBestScore = $totalBest['score'];
883
                            } else {
884
                                $totalBestScore = $totalBest;
885
                            }
886
887
                            $totalBest = ExerciseLib::show_score($totalBestScore[0], $totalBestScore[1], $showPercentage);
888
                        } else {
889
                            $totalBest = $scoredisplay->display_score(
890
                                $totalBest,
891
                                SCORE_DIV,
892
                                SCORE_BOTH,
893
                                true,
894
                                false,
895
                                true
896
                            );
897
                        }
898
                        $row[] = $totalBest;
899
                    }
900
901
                    if (in_array(3, $this->loadStats)) {
902
                        if (isset($defaultData[$categoryId]) && isset($defaultData[$categoryId]['average'])) {
903
                            $totalAverage = $defaultData[$categoryId]['average'];
904
                        } else {
905
                            $averageWeight = 0;
906
                            $categoryAverage = 0;
907
                            foreach ($totalAverageList as $averageScore) {
908
                                $categoryAverage += $averageScore[0];
909
                                $averageWeight += $averageScore[1];
910
                            }
911
                            $categoryAverage = $categoryAverage / count($totalAverageList);
912
                            //$averageWeight = $averageWeight ($totalAverageList);
913
914
                            // Overwrite main weight
915
                            //$totalAverage[0] = $average / count($this->studentList);
916
                            //$totalAverage[1] = $main_weight;
917
                            $totalAverage[0] = $categoryAverage;
918
                            $totalAverage[1] = $averageWeight;
919
                            //$defaultData[$categoryId]['average'] = $totalBest;
920
                        }
921
922
                        if ($useExerciseScoreInTotal) {
923
                            if (isset($totalAverage['score'])) {
924
                                $totalAverageScore = $totalAverage['score'];
925
                            } else {
926
                                $totalAverageScore = $totalAverage;
927
                            }
928
929
                            $totalAverage = ExerciseLib::show_score($totalAverageScore[0], $totalAverageScore[1], $showPercentage);
930
                        } else {
931
                            $totalAverage = $scoredisplay->display_score(
932
                                $totalAverage,
933
                                SCORE_DIV,
934
                                SCORE_BOTH,
935
                                true,
936
                                false,
937
                                true
938
                            );
939
                        }
940
941
                        $row[] = $totalAverage;
942
                    }
943
                }
944
945
                if (!empty($row)) {
946
                    $sortable_data[] = $row;
947
                }
948
            }
949
        }
950
951
        Session::write('default_data', $defaultData);
952
953
        // Warning messages
954
        $view = isset($_GET['view']) ? $_GET['view'] : null;
955
        if ($this->teacherView) {
956
            if (isset($_GET['selectcat']) &&
957
                $_GET['selectcat'] > 0 &&
958
                'presence' !== $view
959
            ) {
960
                $id_cat = (int) $_GET['selectcat'];
961
                $category = Category::load($id_cat);
962
                if (isset($category[0])) {
963
                    $weight_category = (int) $this->build_weight($category[0]);
964
                    $course_code = $this->build_course_code($category[0]);
965
                    $localCourseInfo = api_get_course_info($course_code);
966
                    $localCourseId = $localCourseInfo['real_id'];
967
                    $weight_total_links = round($weight_total_links);
968
969
                    if ($weight_total_links > $weight_category ||
970
                        $weight_total_links < $weight_category ||
971
                        $weight_total_links > $weight_category
972
                    ) {
973
                        $warning_message = sprintf(get_lang('The sum of all weights of activities must be %s'), $weight_category);
974
                        $modify_icons =
975
                            '<a href="gradebook_edit_cat.php?editcat='.$id_cat.'&cid='.$localCourseId.'&sid='.api_get_session_id().'">'.
976
                            Display::getMdiIcon(ActionIcon::EDIT, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Edit'), ['alt' => $warning_message]);
977
                        $warning_message .= $modify_icons;
978
                        echo Display::return_message($warning_message, 'warning', false);
979
                    }
980
981
                    $content_html = DocumentManager::replace_user_info_into_html(
982
                        api_get_user_id(),
983
                        $localCourseInfo,
984
                        api_get_session_id()
985
                    );
986
987
                    if (!empty($content_html)) {
988
                        $new_content = explode('</head>', $content_html['content']);
989
                    }
990
991
                    if (empty($new_content[0])) {
992
                        // Set default certificate
993
                        DocumentManager::generateDefaultCertificate($localCourseInfo);
994
                    }
995
                }
996
            }
997
998
            if (empty($_GET['selectcat'])) {
999
                $categories = Category::load();
1000
                $weight_categories = $certificate_min_scores = $course_codes = [];
1001
                foreach ($categories as $category) {
1002
                    $course_code_category = $this->build_course_code($category);
1003
                    if (!empty($course_code)) {
1004
                        if ($course_code_category == $course_code) {
1005
                            $weight_categories[] = intval($this->build_weight($category));
1006
                            $certificate_min_scores[] = intval($this->build_certificate_min_score($category));
1007
                            $course_codes[] = $course_code;
1008
                            break;
1009
                        }
1010
                    } else {
1011
                        $weight_categories[] = intval($this->build_weight($category));
1012
                        $certificate_min_scores[] = intval($this->build_certificate_min_score($category));
1013
                        $course_codes[] = $course_code_category;
1014
                    }
1015
                }
1016
1017
                if (is_array($weight_categories) &&
1018
                    is_array($certificate_min_scores) &&
1019
                    is_array($course_codes)
1020
                ) {
1021
                    $warning_message = '';
1022
                    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...
1023
                        $weight_category = intval($weight_categories[$x]);
1024
                        $certificate_min_score = intval($certificate_min_scores[$x]);
1025
                        $course_code = $course_codes[$x];
1026
1027
                        if (empty($certificate_min_score) ||
1028
                            ($certificate_min_score > $weight_category)
1029
                        ) {
1030
                            $warning_message .= $course_code.
1031
                                '&nbsp;-&nbsp;'.get_lang('Certificate minimum score is required and must not be more than').
1032
                                '&nbsp;'.$weight_category.'<br />';
1033
                        }
1034
                    }
1035
1036
                    if (!empty($warning_message)) {
1037
                        echo Display::return_message($warning_message, 'warning', false);
1038
                    }
1039
                }
1040
            }
1041
        }
1042
1043
        return $sortable_data;
1044
    }
1045
1046
    /**
1047
     * @return string
1048
     */
1049
    public function getGraph()
1050
    {
1051
        $data = $this->getDataForGraph();
1052
        if (!empty($data) &&
1053
            isset($data['categories']) &&
1054
            isset($data['my_result']) &&
1055
            isset($data['average'])
1056
        ) {
1057
            $dataSet = new pData();
1058
            $dataSet->addPoints($data['my_result'], get_lang('Me'));
1059
            // In order to generate random values
1060
            // $data['average'] = array(rand(0,50), rand(0,50));
1061
            $dataSet->addPoints($data['average'], get_lang('Average'));
1062
            $dataSet->addPoints($data['categories'], 'categories');
1063
            $dataSet->setAbscissa('categories');
1064
            $xSize = 700;
1065
            $ySize = 500;
1066
            $pChart = new pImage($xSize, $ySize, $dataSet);
1067
            /* Turn of Antialiasing */
1068
            $pChart->Antialias = false;
1069
1070
            /* Add a border to the picture */
1071
            $pChart->drawRectangle(
1072
                0,
1073
                0,
1074
                $xSize - 1,
1075
                $ySize - 1,
1076
                ["R" => 0, "G" => 0, "B" => 0]
1077
            );
1078
            $pChart->drawText(
1079
                80,
1080
                16,
1081
                get_lang('Results and feedback'),
1082
                ["FontSize" => 11, "Align" => TEXT_ALIGN_BOTTOMMIDDLE]
1083
            );
1084
            $pChart->setGraphArea(50, 30, $xSize - 50, $ySize - 70);
1085
            $pChart->setFontProperties(
1086
                [
1087
                    'FontName' => api_get_path(SYS_FONTS_PATH).'Harmattan/Harmattan-Regular.ttf',
1088
                    /*'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',*/
1089
                    'FontSize' => 10,
1090
                ]
1091
            );
1092
1093
            /* Draw the scale */
1094
            $scaleSettings = [
1095
                "XMargin" => AUTO,
1096
                "YMargin" => 10,
1097
                "Floating" => true,
1098
                "GridR" => 200,
1099
                "GridG" => 200,
1100
                "GridB" => 200,
1101
                "DrawSubTicks" => true,
1102
                "CycleBackground" => true,
1103
                'LabelRotation' => 10,
1104
            ];
1105
            $pChart->drawScale($scaleSettings);
1106
1107
            /* Draw the line chart */
1108
            $pChart->drawLineChart();
1109
            $pChart->drawPlotChart(
1110
                [
1111
                    "DisplayValues" => true,
1112
                    "PlotBorder" => true,
1113
                    "BorderSize" => 2,
1114
                    "Surrounding" => -60,
1115
                    "BorderAlpha" => 80,
1116
                ]
1117
            );
1118
1119
            /* Write the chart legend */
1120
            $pChart->drawLegend(
1121
                $xSize - 180,
1122
                9,
1123
                [
1124
                    "Style" => LEGEND_NOBORDER,
1125
                    "Mode" => LEGEND_HORIZONTAL,
1126
                    "FontR" => 0,
1127
                    "FontG" => 0,
1128
                    "FontB" => 0,
1129
                ]
1130
            );
1131
1132
            $cachePath = api_get_path(SYS_ARCHIVE_PATH);
1133
            $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
1134
            $chartHash = $myCache->getHash($dataSet);
1135
1136
            $myCache->writeToCache($chartHash, $pChart);
1137
            $imgSysPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
1138
            $myCache->saveFromCache($chartHash, $imgSysPath);
1139
            $imgWebPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
1140
1141
            if (file_exists($imgSysPath)) {
1142
                $result = '<br /><div id="contentArea" style="text-align: center;" >';
1143
                $result .= '<img src="'.$imgWebPath.'" >';
1144
                $result .= '</div>';
1145
1146
                return $result;
1147
            }
1148
        }
1149
1150
        return '';
1151
    }
1152
1153
    /**
1154
     * @return array
1155
     */
1156
    private function getDataForGraph()
1157
    {
1158
        return $this->dataForGraph;
1159
    }
1160
1161
    /**
1162
     * @param $item
1163
     *
1164
     * @return mixed
1165
     */
1166
    private function build_certificate_min_score($item)
1167
    {
1168
        return $item->getCertificateMinScore();
1169
    }
1170
1171
    /**
1172
     * @param $item
1173
     *
1174
     * @return mixed
1175
     */
1176
    private function build_weight($item)
1177
    {
1178
        return $item->get_weight();
1179
    }
1180
1181
    /**
1182
     * @param $item
1183
     *
1184
     * @return mixed
1185
     */
1186
    private function build_course_code($item)
1187
    {
1188
        return $item->get_course_code();
1189
    }
1190
1191
    /**
1192
     * @param $item
1193
     *
1194
     * @return string
1195
     */
1196
    private function build_id_column($item)
1197
    {
1198
        switch ($item->get_item_type()) {
1199
            // category
1200
            case 'C':
1201
                return 'CATE'.$item->get_id();
1202
            // evaluation
1203
            case 'E':
1204
                return 'EVAL'.$item->get_id();
1205
            // link
1206
            case 'L':
1207
                return 'LINK'.$item->get_id();
1208
        }
1209
    }
1210
1211
    /**
1212
     * @param $item
1213
     * @param string $style
1214
     *
1215
     * @return string
1216
     */
1217
    private function build_type_column($item, $style = null)
1218
    {
1219
        return GradebookUtils::build_type_icon_tag($item->get_icon_name(), $style);
1220
    }
1221
1222
    /**
1223
     * Generate name column.
1224
     *
1225
     * @param GradebookItem $item
1226
     * @param string        $type simple|detail
1227
     *
1228
     * @return string
1229
     */
1230
    private function build_name_link($item, $type = 'detail', $spaces = 0)
1231
    {
1232
        $view = isset($_GET['view']) ? Security::remove_XSS($_GET['view']) : null;
1233
        $categoryId = $item->getCategory()->get_id();
1234
        $is_student = api_is_student();
1235
        $cat = new Category();
1236
1237
        switch ($item->get_item_type()) {
1238
            case 'C':
1239
                /** @var Category $item */
1240
                $prms_uri = '?selectcat='.$item->get_id().'&view='.$view;
1241
                $isStudentView = api_is_student_view_active();
1242
                if (isset($is_student) || $isStudentView) {
1243
                    $prms_uri = $prms_uri.'&amp;isStudentView=studentview';
1244
                }
1245
                $show_message = Category::show_message_resource_delete($item->getCourseId());
1246
1247
                return '&nbsp;<a href="'.Category::getUrl().$prms_uri.'">'
1248
                    .$item->get_name()
1249
                    .'</a>'
1250
                    .($item->is_course() ? ' &nbsp;['.$item->get_course_code().']'.$show_message : '');
1251
            case 'E':
1252
                // Evaluation
1253
                $course_id = CourseManager::get_course_by_category($categoryId);
1254
                $show_message = Category::show_message_resource_delete($course_id);
1255
1256
                // course/platform admin can go to the view_results page
1257
                if (api_is_allowed_to_edit() && empty($show_message)) {
1258
                    if ('presence' == $item->get_type()) {
1259
                        return '&nbsp;'
1260
                            .'<a href="gradebook_view_result.php?cidReq='.$course_id.'&amp;selecteval='.$item->get_id().'">'
1261
                            .$item->get_name()
1262
                            .'</a>';
1263
                    } else {
1264
                        $extra = Display::label(get_lang('Score'));
1265
                        if ('simple' == $type) {
1266
                            $extra = '';
1267
                        }
1268
1269
                        return '&nbsp;'
1270
                            .'<a href="gradebook_view_result.php?'.api_get_cidreq().'&selecteval='.$item->get_id().'">'
1271
                            .$item->get_name()
1272
                            .'</a>&nbsp;'.$extra;
1273
                    }
1274
                } elseif (ScoreDisplay::instance()->is_custom() && empty($show_message)) {
1275
                    // students can go to the statistics page (if custom display enabled)
1276
                    return '&nbsp;'
1277
                        .'<a href="gradebook_statistics.php?'.api_get_cidreq().'&selecteval='.$item->get_id().'">'
1278
                        .$item->get_name()
1279
                        .'</a>';
1280
                } elseif (empty($show_message) && !api_is_allowed_to_edit() && !ScoreDisplay::instance()->is_custom()) {
1281
                    return '&nbsp;'
1282
                        .'<a href="gradebook_statistics.php?'.api_get_cidreq().'&selecteval='.$item->get_id().'">'
1283
                        .$item->get_name()
1284
                        .'</a>';
1285
                } else {
1286
                    return '['.get_lang('Score').']&nbsp;&nbsp;'.$item->get_name().$show_message;
1287
                }
1288
                // no break because of return
1289
            case 'L':
1290
                // Link
1291
                $course_id = CourseManager::get_course_by_category($categoryId);
1292
                $show_message = Category::show_message_resource_delete($course_id);
1293
1294
                $url = $item->get_link();
1295
                $text = $item->get_name();
1296
                if (isset($url) && empty($show_message)) {
1297
                    $text = '&nbsp;<a href="'.$item->get_link().'">'
1298
                        .$item->get_name()
1299
                        .'</a>';
1300
                }
1301
1302
                $extra = Display::label($item->get_type_name(), 'info');
1303
                if ('simple' === $type) {
1304
                    $extra = '';
1305
                }
1306
                $extra .= $item->getSkillsFromItem();
1307
                $text .= "&nbsp;".$extra.$show_message;
1308
1309
                /*if ($item instanceof ExerciseLink) {
1310
                    $spaces = str_repeat('&nbsp;', $spaces);
1311
                    $text .= '<br /><br />'.$spaces.$item->getLpListToString();
1312
                }*/
1313
1314
                $cc = $this->currentcat->get_course_code();
1315
                if (empty($cc)) {
1316
                    $text .= '&nbsp;[<a href="'.api_get_path(REL_COURSE_PATH).$item->get_course_code().'/">'.$item->get_course_code().'</a>]';
1317
                }
1318
1319
                return $text;
1320
        }
1321
    }
1322
1323
    /**
1324
     * @param AbstractLink $item
1325
     *
1326
     * @return string|null
1327
     */
1328
    private function build_edit_column($item)
1329
    {
1330
        switch ($item->get_item_type()) {
1331
            case 'C':
1332
                // Category
1333
                return GradebookUtils::build_edit_icons_cat($item, $this->currentcat);
1334
            case 'E':
1335
                // Evaluation
1336
                return GradebookUtils::build_edit_icons_eval($item, $this->currentcat->get_id());
1337
            case 'L':
1338
                // Link
1339
                return GradebookUtils::build_edit_icons_link($item, $this->currentcat->get_id());
1340
        }
1341
    }
1342
}
1343