Passed
Push — master ( 49c89f...65060b )
by Julito
10:01
created

FlatViewTable   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 500
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 284
c 0
b 0
f 0
dl 0
loc 500
rs 6.4799
wmc 54

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getMainCourseCategory() 0 3 1
A setLimitEnabled() 0 3 1
A __construct() 0 35 3
F get_table_data() 0 169 23
A build_name_link() 0 3 1
A get_total_number_of_items() 0 3 1
F display_graph_by_resource() 0 232 24

How to fix   Complexity   

Complex Class

Complex classes like FlatViewTable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

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

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

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
set_time_limit(0);
5
6
use CpChart\Cache as pCache;
7
use CpChart\Data as pData;
8
use CpChart\Image as pImage;
9
10
/**
11
 * Class FlatViewTable
12
 * Table to display flat view (all evaluations and links for all students).
13
 *
14
 * @author Stijn Konings
15
 * @author Bert Steppé  - (refactored, optimised)
16
 * @author Julio Montoya Armas - Gradebook Graphics
17
 *
18
 * @package chamilo.gradebook
19
 */
20
class FlatViewTable extends SortableTable
21
{
22
    public $datagen;
23
    private $selectcat;
24
    private $limit_enabled;
25
    private $offset;
26
    private $mainCourseCategory;
27
28
    /**
29
     * @param Category $selectcat
30
     * @param array    $users
31
     * @param array    $evals
32
     * @param array    $links
33
     * @param bool     $limit_enabled
34
     * @param int      $offset
35
     * @param null     $addparams
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $addparams is correct as it would always require null to be passed?
Loading history...
36
     * @param Category $mainCourseCategory
37
     */
38
    public function __construct(
39
        $selectcat,
40
        $users = [],
41
        $evals = [],
42
        $links = [],
43
        $limit_enabled = false,
44
        $offset = 0,
45
        $addparams = null,
46
        $mainCourseCategory = null
47
    ) {
48
        parent:: __construct(
49
            'flatviewlist',
50
            null,
51
            null,
52
            api_is_western_name_order() ? 1 : 0
53
        );
54
55
        $this->selectcat = $selectcat;
56
        $this->datagen = new FlatViewDataGenerator(
57
            $users,
58
            $evals,
59
            $links,
60
            ['only_subcat' => $this->selectcat->get_id()],
61
            $mainCourseCategory
62
        );
63
64
        $this->limit_enabled = $limit_enabled;
65
        $this->offset = $offset;
66
        if (isset($addparams)) {
67
            $this->set_additional_parameters($addparams);
68
        }
69
70
        // step 2: generate rows: students
71
        $this->datagen->category = $this->selectcat;
72
        $this->mainCourseCategory = $mainCourseCategory;
73
    }
74
75
    /**
76
     * @param bool $value
77
     */
78
    public function setLimitEnabled($value)
79
    {
80
        $this->limit_enabled = (bool) $value;
81
    }
82
83
    /**
84
     * @return Category
85
     */
86
    public function getMainCourseCategory()
87
    {
88
        return $this->mainCourseCategory;
89
    }
90
91
    /**
92
     * Display gradebook graphs.
93
     */
94
    public function display_graph_by_resource()
95
    {
96
        $headerName = $this->datagen->get_header_names();
97
        $total_users = $this->datagen->get_total_users_count();
98
99
        $displayscore = ScoreDisplay::instance();
100
        $customdisplays = $displayscore->get_custom_score_display_settings();
101
102
        if (empty($customdisplays)) {
103
            echo get_lang('ToViewGraphScoreRuleMustBeEnabled');
104
105
            return '';
106
        }
107
108
        $user_results = $this->datagen->get_data_to_graph2(false);
109
110
        if (empty($user_results) || empty($total_users)) {
111
            echo get_lang('NoResults');
112
113
            return '';
114
        }
115
116
        // Removing first name
117
        array_shift($headerName);
118
        // Removing last name
119
        array_shift($headerName);
120
        // Removing username
121
        array_shift($headerName);
122
123
        $pre_result = $new_result = [];
124
        foreach ($user_results as $result) {
125
            for ($i = 0; $i < count($headerName); $i++) {
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...
126
                if (isset($result[$i + 1])) {
127
                    $pre_result[$i + 3][] = $result[$i + 1];
128
                }
129
            }
130
        }
131
132
        $i = 0;
133
        $resource_list = [];
134
        $pre_result2 = [];
135
136
        foreach ($pre_result as $key => $res_array) {
137
            rsort($res_array);
138
            $pre_result2[] = $res_array;
139
        }
140
141
        //@todo when a display custom does not exist the order of the color does not match
142
        //filling all the answer that are not responded with 0
143
        rsort($customdisplays);
144
145
        if ($total_users > 0) {
146
            foreach ($pre_result2 as $key => $res_array) {
147
                $key_list = [];
148
                foreach ($res_array as $user_result) {
149
                    $userResult = isset($user_result[1]) ? $user_result[1] : null;
150
                    if (!isset($resource_list[$key][$userResult])) {
151
                        $resource_list[$key][$userResult] = 0;
152
                    }
153
                    $resource_list[$key][$userResult]++;
154
                    $key_list[] = $userResult;
155
                }
156
157
                foreach ($customdisplays as $display) {
158
                    if (!in_array($display['display'], $key_list)) {
159
                        $resource_list[$key][$display['display']] = 0;
160
                    }
161
                }
162
                $i++;
163
            }
164
        }
165
166
        //fixing $resource_list
167
        $max = 0;
168
        $new_list = [];
169
        foreach ($resource_list as $key => $value) {
170
            $new_value = [];
171
            foreach ($customdisplays as $item) {
172
                if ($value[$item['display']] > $max) {
173
                    $max = $value[$item['display']];
174
                }
175
                $new_value[$item['display']] = strip_tags($value[$item['display']]);
176
            }
177
            $new_list[] = $new_value;
178
        }
179
        $resource_list = $new_list;
180
181
        $i = 1;
182
183
        foreach ($resource_list as $key => $resource) {
184
            // Reverse array, otherwise we get highest values first
185
            $resource = array_reverse($resource, true);
186
187
            $dataSet = new pData();
188
            $dataSet->addPoints($resource, 'Serie');
189
            $dataSet->addPoints(array_keys($resource), 'Labels');
190
            $header = $headerName[$i - 1];
191
            if (is_array($header) && isset($header['header'])) {
192
                $header = $header['header'];
193
            }
194
            $dataSet->setSerieDescription('Labels', strip_tags($header));
195
            $dataSet->setAbscissa('Labels');
196
            $dataSet->setAbscissaName(get_lang('GradebookSkillsRanking'));
197
            $dataSet->setAxisName(0, get_lang('Students'));
198
            $palette = [
199
                '0' => ['R' => 186, 'G' => 206, 'B' => 151, 'Alpha' => 100],
200
                '1' => ['R' => 210, 'G' => 148, 'B' => 147, 'Alpha' => 100],
201
                '2' => ['R' => 148, 'G' => 170, 'B' => 208, 'Alpha' => 100],
202
                '3' => ['R' => 221, 'G' => 133, 'B' => 61, 'Alpha' => 100],
203
                '4' => ['R' => 65, 'G' => 153, 'B' => 176, 'Alpha' => 100],
204
                '5' => ['R' => 114, 'G' => 88, 'B' => 144, 'Alpha' => 100],
205
                '6' => ['R' => 138, 'G' => 166, 'B' => 78, 'Alpha' => 100],
206
                '7' => ['R' => 171, 'G' => 70, 'B' => 67, 'Alpha' => 100],
207
                '8' => ['R' => 69, 'G' => 115, 'B' => 168, 'Alpha' => 100],
208
            ];
209
            // Cache definition
210
            $cachePath = api_get_path(SYS_ARCHIVE_PATH);
211
            $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
212
            $chartHash = $myCache->getHash($dataSet);
213
            if ($myCache->isInCache($chartHash)) {
214
                $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
215
                $myCache->saveFromCache($chartHash, $imgPath);
216
                $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
217
            } else {
218
                /* Create the pChart object */
219
                $widthSize = 480;
220
                $heightSize = 250;
221
222
                $myPicture = new pImage($widthSize, $heightSize, $dataSet);
223
224
                /* Turn of Antialiasing */
225
                $myPicture->Antialias = false;
226
227
                /* Add a border to the picture */
228
                $myPicture->drawRectangle(
229
                    0,
230
                    0,
231
                    $widthSize - 1,
232
                    $heightSize - 1,
233
                    [
234
                        'R' => 0,
235
                        'G' => 0,
236
                        'B' => 0,
237
                    ]
238
                );
239
240
                /* Set the default font */
241
                $myPicture->setFontProperties(
242
                    [
243
                        'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
244
                        'FontSize' => 10,
245
                    ]
246
                );
247
248
                /* Write the chart title */
249
                $myPicture->drawText(
250
                    250,
251
                    30,
252
                    strip_tags($header),
253
                    [
254
                        'FontSize' => 12,
255
                        'Align' => TEXT_ALIGN_BOTTOMMIDDLE,
0 ignored issues
show
Bug introduced by
The constant TEXT_ALIGN_BOTTOMMIDDLE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
256
                    ]
257
                );
258
259
                /* Define the chart area */
260
                $myPicture->setGraphArea(50, 40, $widthSize - 20, $heightSize - 50);
261
262
                /* Draw the scale */
263
                $scaleSettings = [
264
                    'GridR' => 200,
265
                    'GridG' => 200,
266
                    'GridB' => 200,
267
                    'DrawSubTicks' => true,
268
                    'CycleBackground' => true,
269
                    'Mode' => SCALE_MODE_START0,
0 ignored issues
show
Bug introduced by
The constant SCALE_MODE_START0 was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
270
                ];
271
                $myPicture->drawScale($scaleSettings);
272
273
                /* Turn on shadow computing */
274
                $myPicture->setShadow(
275
                    true,
276
                    [
277
                        'X' => 1,
278
                        'Y' => 1,
279
                        'R' => 0,
280
                        'G' => 0,
281
                        'B' => 0,
282
                        'Alpha' => 10,
283
                    ]
284
                );
285
286
                /* Draw the chart */
287
                $myPicture->setShadow(
288
                    true,
289
                    [
290
                        'X' => 1,
291
                        'Y' => 1,
292
                        'R' => 0,
293
                        'G' => 0,
294
                        'B' => 0,
295
                        'Alpha' => 10,
296
                    ]
297
                );
298
                $settings = [
299
                    'OverrideColors' => $palette,
300
                    'Gradient' => false,
301
                    'GradientMode' => GRADIENT_SIMPLE,
0 ignored issues
show
Bug introduced by
The constant GRADIENT_SIMPLE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
302
                    'DisplayPos' => LABEL_POS_TOP,
0 ignored issues
show
Bug introduced by
The constant LABEL_POS_TOP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
303
                    'DisplayValues' => true,
304
                    'DisplayR' => 0,
305
                    'DisplayG' => 0,
306
                    'DisplayB' => 0,
307
                    'DisplayShadow' => true,
308
                    'Surrounding' => 10,
309
                ];
310
                $myPicture->drawBarChart($settings);
311
312
                /* Render the picture (choose the best way) */
313
314
                $myCache->writeToCache($chartHash, $myPicture);
315
                $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
316
                $myCache->saveFromCache($chartHash, $imgPath);
317
                $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
318
            }
319
            echo '<img src="'.$imgPath.'" >';
320
            if ($i % 2 == 0 && $i != 0) {
321
                echo '<br /><br />';
322
            } else {
323
                echo '&nbsp;&nbsp;&nbsp;';
324
            }
325
            $i++;
326
        }
327
    }
328
329
    /**
330
     * Function used by SortableTable to get total number of items in the table.
331
     */
332
    public function get_total_number_of_items()
333
    {
334
        return $this->datagen->get_total_users_count();
335
    }
336
337
    /**
338
     * Function used by SortableTable to generate the data to display.
339
     */
340
    public function get_table_data(
341
        $from = 1,
342
        $per_page = null,
343
        $column = null,
344
        $direction = null,
345
        $sort = null
346
    ) {
347
        $is_western_name_order = api_is_western_name_order();
348
349
        // create page navigation if needed
350
        $totalitems = $this->datagen->get_total_items_count();
351
352
        if ($this->limit_enabled && $totalitems > GRADEBOOK_ITEM_LIMIT) {
353
            $selectlimit = GRADEBOOK_ITEM_LIMIT;
354
        } else {
355
            $selectlimit = $totalitems;
356
        }
357
358
        $header = null;
359
        if ($this->limit_enabled && $totalitems > GRADEBOOK_ITEM_LIMIT) {
360
            $header .= '<table style="width: 100%; text-align: right; margin-left: auto; margin-right: auto;" border="0" cellpadding="2">'
361
                .'<tbody>'
362
                .'<tr>';
363
364
            // previous X
365
            $header .= '<td style="width:100%;">';
366
            if ($this->offset >= GRADEBOOK_ITEM_LIMIT) {
367
                $header .= '<a href="'.api_get_self()
368
                    .'?selectcat='.Security::remove_XSS($_GET['selectcat'])
369
                    .'&offset='.(($this->offset) - GRADEBOOK_ITEM_LIMIT)
370
                    .(isset($_GET['search']) ? '&search='.Security::remove_XSS($_GET['search']) : '').'">'
371
                    .Display::return_icon(
372
                        'action_prev.png',
373
                        get_lang('PreviousPage'),
374
                        [],
375
                        ICON_SIZE_MEDIUM
376
                    )
377
                    .'</a>';
378
            } else {
379
                $header .= Display::return_icon(
380
                    'action_prev_na.png',
381
                    get_lang('PreviousPage'),
382
                    [],
383
                    ICON_SIZE_MEDIUM
384
                );
385
            }
386
            $header .= ' ';
387
            // next X
388
            $calcnext = (($this->offset + (2 * GRADEBOOK_ITEM_LIMIT)) > $totalitems) ?
389
                ($totalitems - (GRADEBOOK_ITEM_LIMIT + $this->offset)) : GRADEBOOK_ITEM_LIMIT;
390
391
            if ($calcnext > 0) {
392
                $header .= '<a href="'.api_get_self()
393
                    .'?selectcat='.Security::remove_XSS($_GET['selectcat'])
394
                    .'&offset='.($this->offset + GRADEBOOK_ITEM_LIMIT)
395
                    .(isset($_GET['search']) ? '&search='.Security::remove_XSS($_GET['search']) : '').'">'
396
                    .Display::return_icon('action_next.png', get_lang('NextPage'), [], ICON_SIZE_MEDIUM)
397
                    .'</a>';
398
            } else {
399
                $header .= Display::return_icon(
400
                    'action_next_na.png',
401
                    get_lang('NextPage'),
402
                    [],
403
                    ICON_SIZE_MEDIUM
404
                );
405
            }
406
            $header .= '</td>';
407
            $header .= '</tbody></table>';
408
            echo $header;
409
        }
410
411
        // retrieve sorting type
412
        if ($is_western_name_order) {
413
            $users_sorting = ($this->column == 0 ? FlatViewDataGenerator::FVDG_SORT_FIRSTNAME : FlatViewDataGenerator::FVDG_SORT_LASTNAME);
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $this->column of type integer|mixed|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
414
        } else {
415
            $users_sorting = ($this->column == 0 ? FlatViewDataGenerator::FVDG_SORT_LASTNAME : FlatViewDataGenerator::FVDG_SORT_FIRSTNAME);
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $this->column of type integer|mixed|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
416
        }
417
418
        if ($this->direction == 'DESC') {
419
            $users_sorting |= FlatViewDataGenerator::FVDG_SORT_DESC;
420
        } else {
421
            $users_sorting |= FlatViewDataGenerator::FVDG_SORT_ASC;
422
        }
423
424
        // step 1: generate columns: evaluations and links
425
        $header_names = $this->datagen->get_header_names($this->offset, $selectlimit);
426
        $userRowSpan = false;
427
        foreach ($header_names as $item) {
428
            if (is_array($item)) {
429
                $userRowSpan = true;
430
                break;
431
            }
432
        }
433
434
        $thAttributes = '';
435
        if ($userRowSpan) {
436
            $thAttributes = 'rowspan=2';
437
        }
438
439
        $this->set_header(0, $header_names[0], true, $thAttributes);
440
        $this->set_header(1, $header_names[1], true, $thAttributes);
441
442
        $column = 2;
443
        $firstHeader = [];
444
        while ($column < count($header_names)) {
445
            $headerData = $header_names[$column];
446
447
            if (is_array($headerData)) {
448
                $countItems = count($headerData['items']);
449
450
                $this->set_header(
451
                    $column,
452
                    $headerData['header'],
453
                    false,
454
                    'colspan="'.$countItems.'"'
455
                );
456
457
                foreach ($headerData['items'] as $item) {
458
                    $firstHeader[] = '<center>'.$item.'</center>';
459
                }
460
            } else {
461
                $this->set_header($column, $headerData, false, $thAttributes);
462
            }
463
            $column++;
464
        }
465
466
        $data_array = $this->datagen->get_data(
467
            $users_sorting,
468
            $from,
469
            $this->per_page,
0 ignored issues
show
Bug introduced by
It seems like $this->per_page can also be of type integer; however, parameter $users_count of FlatViewDataGenerator::get_data() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

469
            /** @scrutinizer ignore-type */ $this->per_page,
Loading history...
470
            $this->offset,
471
            $selectlimit
472
        );
473
474
        $table_data = [];
475
476
        if (!empty($firstHeader)) {
477
            $table_data[] = $firstHeader;
478
        }
479
480
        foreach ($data_array as $user_row) {
481
            $user_id = $user_row[0];
482
            unset($user_row[0]);
483
            $userInfo = api_get_user_info($user_id);
484
            if ($is_western_name_order) {
485
                $user_row[1] = $this->build_name_link(
486
                    $user_id,
487
                    $userInfo['firstname']
488
                );
489
                $user_row[2] = $this->build_name_link(
490
                    $user_id,
491
                    $userInfo['lastname']
492
                );
493
            } else {
494
                $user_row[1] = $this->build_name_link(
495
                    $user_id,
496
                    $userInfo['lastname']
497
                );
498
                $user_row[2] = $this->build_name_link(
499
                    $user_id,
500
                    $userInfo['firstname']
501
                );
502
            }
503
            $user_row = array_values($user_row);
504
505
            $table_data[] = $user_row;
506
        }
507
508
        return $table_data;
509
    }
510
511
    /**
512
     * @param $userId
513
     * @param $name
514
     *
515
     * @return string
516
     */
517
    private function build_name_link($userId, $name)
518
    {
519
        return '<a href="user_stats.php?userid='.$userId.'&selectcat='.$this->selectcat->get_id().'&'.api_get_cidreq().'">'.$name.'</a>';
520
    }
521
}
522