TableSort::sort_table_config()   F
last analyzed

Complexity

Conditions 31
Paths 1022

Size

Total Lines 112
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 31
eloc 61
nc 1022
nop 7
dl 0
loc 112
rs 0
c 0
b 0
f 0

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