Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/gradebook/lib/fe/gradebooktable.class.php (1 issue)

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