Completed
Push — master ( 7bef58...5c053f )
by Julito
25:30
created

TableSort::getSortFunction()   C

Complexity

Conditions 10
Paths 10

Size

Total Lines 62
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 42
c 0
b 0
f 0
nop 3
dl 0
loc 62
rs 6.4192
nc 10

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * This is a library with some functions to sort tabular data.
6
 *
7
 * @package chamilo.library
8
 */
9
define('SORT_DATE', 3);
10
define('SORT_IMAGE', 4);
11
12
/**
13
 * Class TableSort.
14
 */
15
class TableSort
16
{
17
    /**
18
     * Sorts 2-dimensional table.
19
     *
20
     * @param array $data      the data to be sorted
21
     * @param int   $column    The column on which the data should be sorted (default = 0)
22
     * @param int   $direction The direction to sort (SORT_ASC (default) or SORT_DESC)
23
     * @param int   $type      How should data be sorted (SORT_REGULAR, SORT_NUMERIC,
24
     *                         SORT_STRING,SORT_DATE,SORT_IMAGE)
25
     *
26
     * @return array The sorted dataset
27
     *
28
     * @author [email protected]
29
     */
30
    public static function sort_table(
31
        $data,
32
        $column = 0,
33
        $direction = SORT_ASC,
34
        $type = SORT_REGULAR
35
    ) {
36
        if (!is_array($data) || empty($data)) {
37
            return [];
38
        }
39
        if ($column != strval(intval($column))) {
40
            // Probably an attack
41
            return $data;
42
        }
43
        if (!in_array($direction, [SORT_ASC, SORT_DESC])) {
44
            // Probably an attack
45
            return $data;
46
        }
47
48
        if ($type == SORT_REGULAR) {
49
            $type = SORT_STRING;
50
            if (self::is_image_column($data, $column)) {
51
                $type = SORT_IMAGE;
52
            } elseif (self::is_date_column($data, $column)) {
53
                $type = SORT_DATE;
54
            } elseif (self::is_numeric_column($data, $column)) {
55
                $type = SORT_NUMERIC;
56
            }
57
        }
58
        $function = self::getSortFunction($type, $direction, $column);
59
60
        // Sort the content
61
        usort($data, $function);
62
63
        return $data;
64
    }
65
66
    /**
67
     * @param $type
68
     * @param $direction
69
     * @param $column
70
     *
71
     * @return Closure
72
     */
73
    public static function getSortFunction($type, $direction, $column)
74
    {
75
        $compareOperator = $direction == SORT_ASC ? '>' : '<=';
76
77
        switch ($type) {
78
            case SORT_NUMERIC:
79
                $function = function ($a, $b) use ($column, $compareOperator) {
80
                    $result = strip_tags($a[$column]) <= strip_tags($b[$column]);
81
                    if ($compareOperator == '>') {
82
                        $result = strip_tags($a[$column]) > strip_tags($b[$column]);
83
                    }
84
85
                    return $result;
86
                };
87
                break;
88
            case SORT_IMAGE:
89
                $function = function ($a, $b) use ($column, $compareOperator) {
90
                    $result = api_strnatcmp(
91
                        api_strtolower(strip_tags($a[$column], "<img>")),
92
                        api_strtolower(strip_tags($b[$column], "<img>"))
93
                    ) <= 0;
94
                    if ($compareOperator == '>') {
95
                        $result = api_strnatcmp(
96
                            api_strtolower(strip_tags($a[$column], "<img>")),
97
                            api_strtolower(strip_tags($b[$column], "<img>"))
98
                        ) > 0;
99
                    }
100
101
                    return $result;
102
                };
103
104
                break;
105
            case SORT_DATE:
106
                $function = function ($a, $b) use ($column, $compareOperator) {
107
                    $result = strtotime(strip_tags($a[$column])) <= strtotime(strip_tags($b[$column]));
108
                    if ($compareOperator == '>') {
109
                        $result = strtotime(strip_tags($a[$column])) > strtotime(strip_tags($b[$column]));
110
                    }
111
112
                    return $result;
113
                };
114
                break;
115
            case SORT_STRING:
116
            default:
117
                $function = function ($a, $b) use ($column, $compareOperator) {
118
                    $result = api_strnatcmp(
119
                        api_strtolower(strip_tags($a[$column])),
120
                        api_strtolower(strip_tags($b[$column]))
121
                    ) <= 0;
122
                    if ($compareOperator == '>') {
123
                        $result = api_strnatcmp(
124
                            api_strtolower(strip_tags($a[$column])),
125
                            api_strtolower(strip_tags($b[$column]))
126
                        ) > 0;
127
                    }
128
129
                    return $result;
130
                };
131
                break;
132
        }
133
134
        return $function;
135
    }
136
137
    /**
138
     * Sorts 2-dimensional table. It is possible changing the columns that will be
139
     * shown and the way that the columns are to be sorted.
140
     *
141
     * @param array $data         the data to be sorted
142
     * @param int   $column       The column on which the data should be sorted (default = 0)
143
     * @param int   $direction    The direction to sort (SORT_ASC (default) or SORT_DESC)
144
     * @param array $column_show  The columns that we will show in the table
145
     *                            i.e: $column_show = array('1','0','1') we will show the 1st and the 3th column.
146
     * @param array $column_order Changes how the columns will be sorted
147
     *                            ie. $column_order = array('0','3','2','3') The column [1] will be sorted like the column [3]
148
     * @param int   $type         How should data be sorted (SORT_REGULAR, SORT_NUMERIC, SORT_STRING, SORT_DATE, SORT_IMAGE)
149
     *
150
     * @return array The sorted dataset
151
     *
152
     * @author [email protected]
153
     */
154
    public static function sort_table_config(
155
        $data,
156
        $column = 0,
157
        $direction = SORT_ASC,
158
        $column_show = null,
159
        $column_order = null,
160
        $type = SORT_REGULAR,
161
        $doc_filter = false
162
    ) {
163
        if (!is_array($data) || empty($data)) {
164
            return [];
165
        }
166
167
        if ($column != strval(intval($column))) {
168
            // Probably an attack
169
            return $data;
170
        }
171
172
        if (!in_array($direction, [SORT_ASC, SORT_DESC])) {
173
            // Probably an attack
174
            return $data;
175
        }
176
177
        // Change columns sort
178
        // Here we say that the real way of how the columns are going to be order is manage by the $column_order array
179
        if (is_array($column_order)) {
180
            $column = isset($column_order[$column]) ? $column_order[$column] : $column;
181
        }
182
183
        if ($type == SORT_REGULAR) {
184
            if (self::is_image_column($data, $column)) {
185
                $type = SORT_IMAGE;
186
            } elseif (self::is_date_column($data, $column)) {
187
                $type = SORT_DATE;
188
            } elseif (self::is_numeric_column($data, $column)) {
189
                $type = SORT_NUMERIC;
190
            } else {
191
                $type = SORT_STRING;
192
            }
193
        }
194
195
        //This fixes only works in the document tool when ordering by name
196
        if ($doc_filter && in_array($type, [SORT_STRING])) {
197
            $folder_to_sort = [];
198
            $new_data = [];
199
            if (!empty($data)) {
200
                foreach ($data as $document) {
201
                    if ($document['type'] == 'folder') {
202
                        $docs_to_sort[$document['id']] = api_strtolower($document['name']);
203
                    } else {
204
                        $folder_to_sort[$document['id']] = api_strtolower($document['name']);
205
                    }
206
                    $new_data[$document['id']] = $document;
207
                }
208
209
                if ($direction == SORT_ASC) {
210
                    if (!empty($docs_to_sort)) {
211
                        api_natsort($docs_to_sort);
212
                    }
213
                    if (!empty($folder_to_sort)) {
214
                        api_natsort($folder_to_sort);
215
                    }
216
                } else {
217
                    if (!empty($docs_to_sort)) {
218
                        api_natrsort($docs_to_sort);
219
                    }
220
                    if (!empty($folder_to_sort)) {
221
                        api_natrsort($folder_to_sort);
222
                    }
223
                }
224
225
                $new_data_order = [];
226
                if (!empty($docs_to_sort)) {
227
                    foreach ($docs_to_sort as $id => $document) {
228
                        if (isset($new_data[$id])) {
229
                            $new_data_order[] = $new_data[$id];
230
                        }
231
                    }
232
                }
233
234
                if (!empty($folder_to_sort)) {
235
                    foreach ($folder_to_sort as $id => $document) {
236
                        if (isset($new_data[$id])) {
237
                            $new_data_order[] = $new_data[$id];
238
                        }
239
                    }
240
                }
241
                $data = $new_data_order;
242
            }
243
        } else {
244
            $function = self::getSortFunction($type, $direction, $column);
245
246
            // Sort the content
247
            usort($data, $function);
248
        }
249
250
        if (is_array($column_show) && !empty($column_show)) {
251
            // We show only the columns data that were set up on the $column_show array
252
            $new_order_data = [];
253
            $count_data = count($data);
254
            $count_column_show = count($column_show);
255
            for ($j = 0; $j < $count_data; $j++) {
256
                $k = 0;
257
                for ($i = 0; $i < $count_column_show; $i++) {
258
                    if ($column_show[$i]) {
259
                        $new_order_data[$j][$k] = $data[$j][$i];
260
                    }
261
                    $k++;
262
                }
263
            }
264
            // Replace the multi-arrays
265
            $data = $new_order_data;
266
        }
267
268
        return $data;
269
    }
270
271
    /**
272
     * Checks whether a column of a 2D-array contains only numeric values.
273
     *
274
     * @param array $data   The data-array
275
     * @param int   $column The index of the column to check
276
     *
277
     * @return bool TRUE if column contains only dates, FALSE otherwise
278
     *
279
     * @todo Take locale into account (eg decimal point or comma ?)
280
     *
281
     * @author [email protected]
282
     */
283
    private static function is_numeric_column(&$data, $column)
284
    {
285
        $is_numeric = true;
286
        foreach ($data as $index => &$row) {
287
            $is_numeric &= is_numeric(strip_tags($row[$column]));
288
            if (!$is_numeric) {
289
                break;
290
            }
291
        }
292
293
        return $is_numeric;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $is_numeric also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
294
    }
295
296
    /**
297
     * Checks whether a column of a 2D-array contains only dates (GNU date syntax).
298
     *
299
     * @param array $data   The data-array
300
     * @param int   $column The index of the column to check
301
     *
302
     * @return bool TRUE if column contains only dates, FALSE otherwise
303
     *
304
     * @author [email protected]
305
     */
306
    private static function is_date_column(&$data, $column)
307
    {
308
        $is_date = true;
309
        foreach ($data as $index => &$row) {
310
            if (strlen(strip_tags($row[$column])) != 0) {
311
                $check_date = strtotime(strip_tags($row[$column]));
312
                // strtotime Returns a timestamp on success, FALSE otherwise.
313
                // Previous to PHP 5.1.0, this function would return -1 on failure.
314
                $is_date &= ($check_date != -1 && $check_date);
315
            } else {
316
                $is_date &= false;
317
            }
318
            if (!$is_date) {
319
                break;
320
            }
321
        }
322
323
        return $is_date;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $is_date also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
324
    }
325
326
    /**
327
     * Checks whether a column of a 2D-array contains only images (<img src="path/file.ext" alt=".."/>).
328
     *
329
     * @param array $data   The data-array
330
     * @param int   $column The index of the column to check
331
     *
332
     * @return bool TRUE if column contains only images, FALSE otherwise
333
     *
334
     * @author [email protected]
335
     */
336
    private static function is_image_column(&$data, $column)
337
    {
338
        $is_image = true;
339
        foreach ($data as $index => &$row) {
340
            if (isset($row[$column])) {
341
                // at least one img-tag
342
                $is_image &= strlen(trim(strip_tags($row[$column], '<img>'))) > 0;
343
                // and no text outside attribute-values
344
                $is_image &= strlen(trim(strip_tags($row[$column]))) == 0;
345
            }
346
            if (!$is_image) {
347
                break;
348
            }
349
        }
350
351
        return $is_image;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $is_image also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
352
    }
353
}
354