Passed
Push — 1.11.x ( 40c9d3...8309ba )
by Angel Fernando Quiroz
09:03 queued 33s
created

TableSort::getSortFunction()   D

Complexity

Conditions 20
Paths 10

Size

Total Lines 80
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 48
c 2
b 0
f 0
dl 0
loc 80
rs 4.1666
cc 20
nc 10
nop 3

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