Completed
Pull Request — master (#3115)
by
unknown
02:58
created

sort.php ➔ intl_ksort()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * DokuWiki sort functions
4
 *
5
 * When "intl" extension is available, all sorts are done using a collator.
6
 * Otherwise, primitive PHP functions are called.
7
 *
8
 * The collator is created using the locale given in $conf['lang'].
9
 * It always uses case insensitive "natural" ordering in its collation.
10
 * The fallback solution uses the primitive PHP functions that return almost the same results
11
 * when the input is text with only [A-Za-z0-9] characters.
12
 *
13
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
14
 * @author     Moisés Braga Ribeiro <[email protected]>
15
 */
16
17
/**
18
 * Initialization of a collator using $conf['lang'] as the locale.
19
 * The initialization is done only once, except when $reload is set to TRUE.
20
 * The collation takes "natural ordering" into account, that is, "page 2" is before "page 10".
21
 *
22
 * @param bool $reload Usually FALSE; TRUE forces collator re-creation after a change in $conf['lang']
23
 * @return Collator Returns a configured collator or NULL if the collator cannot be created.
24
 *
25
 * @author Moisés Braga Ribeiro <[email protected]>
26
 */
27
function _get_collator($reload = FALSE) {
28
    global $conf;
29
    static $intl_extension_available = NULL;
30
    static $collator = NULL;
31
32
    if (is_null($intl_extension_available))
33
        $intl_extension_available = class_exists('Collator');
34
    if (!$intl_extension_available)
35
        return NULL;
36
    if ($reload || !isset($collator)) {
37
        $collator = Collator::create($conf['lang']);
38
        if (isset($collator)) {
39
            $collator->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
40
            dbglog('Collator created with locale "' . $conf['lang'] . '": numeric collation on, ' .
41
                   'valid locale "' . $collator->getLocale(Locale::VALID_LOCALE) . '", ' .
42
                   'actual locale "' . $collator->getLocale(Locale::ACTUAL_LOCALE) . '"');
43
        }
44
    }
45
    return $collator;
46
}
47
48
/**
49
 * When $conf['lang'] is changed, this function should be called to re-create the collator
50
 * using the new value.
51
 *
52
 * @author Moisés Braga Ribeiro <[email protected]>
53
 */
54
function lang_has_changed() {
55
    _get_collator(TRUE);
56
}
57
58
/**
59
 * Drop-in replacement for strcmp(), strcasecmp(), strnatcmp() and strnatcasecmp().
60
 * It uses a collator-based comparison, or strnatcasecmp() as a fallback.
61
 *
62
 * @param string $str1 The first string.
63
 * @param string $str2 The second string.
64
 * @return int Returns < 0 if $str1 is less than $str2; > 0 if $str1 is greater than $str2, and 0 if they are equal.
65
 *
66
 * @author Moisés Braga Ribeiro <[email protected]>
67
 */
68
function intl_strcmp($str1, $str2) {
69
    $collator = _get_collator();
70
    if (isset($collator))
71
        return $collator->compare($str1, $str2);
72
    else
73
        return strnatcasecmp($str1, $str2);
74
}
75
76
/**
77
 * Drop-in replacement for sort().
78
 * It uses a collator-based sort, or sort() with flags SORT_NATURAL and SORT_FLAG_CASE as a fallback.
79
 *
80
 * @param array $array The input array.
81
 * @return bool Returns TRUE on success or FALSE on failure.
82
 *
83
 * @author Moisés Braga Ribeiro <[email protected]>
84
 */
85
function intl_sort(&$array) {
86
    $collator = _get_collator();
87
    if (isset($collator))
88
        return $collator->sort($array);
89
    else
90
        return sort($array, SORT_NATURAL | SORT_FLAG_CASE);
91
}
92
93
/**
94
 * Drop-in replacement for ksort().
95
 * It uses a collator-based sort, or ksort() with flags SORT_NATURAL and SORT_FLAG_CASE as a fallback.
96
 *
97
 * @param array $array The input array.
98
 * @return bool Returns TRUE on success or FALSE on failure.
99
 *
100
 * @author Moisés Braga Ribeiro <[email protected]>
101
 */
102
function intl_ksort(&$array) {
103
    $collator = _get_collator();
104
    if (isset($collator))
105
        return uksort($array, array($collator, 'compare'));
106
    else
107
        return ksort($array, SORT_NATURAL | SORT_FLAG_CASE);
108
}
109
110
/**
111
 * Drop-in replacement for asort(), natsort() and natcasesort().
112
 * It uses a collator-based sort, or asort() with flags SORT_NATURAL and SORT_FLAG_CASE as a fallback.
113
 *
114
 * @param array $array The input array.
115
 * @return bool Returns TRUE on success or FALSE on failure.
116
 *
117
 * @author Moisés Braga Ribeiro <[email protected]>
118
 */
119
function intl_asort(&$array) {
120
    $collator = _get_collator();
121
    if (isset($collator))
122
        return $collator->asort($array);
123
    else
124
        return asort($array, SORT_NATURAL | SORT_FLAG_CASE);
125
}
126
127
/**
128
 * Drop-in replacement for asort(), natsort() and natcasesort() when the parameter is an array of filenames.
129
 * Filenames may not be equal to page names, depending on the setting in $conf['fnencode'],
130
 * so the correct behavior is to sort page names and reflect this sorting in the filename array.
131
 *
132
 * @param array $array The input array.
133
 * @return bool Returns TRUE on success or FALSE on failure.
134
 *
135
 * @author Moisés Braga Ribeiro <[email protected]>
136
 */
137
function intl_asortFN(&$array) {
138
    $collator = _get_collator();
139
    if (isset($collator))
140
        return uasort($array, '_sort_filenames_with_collator');
141
    else
142
        return uasort($array, '_sort_filenames_without_collator');
143
}
144
145
/**
146
 * Collator-based string comparison for filenames.
147
 * The filenames are converted to page names with utf8_decodeFN() before the comparison.
148
 * 
149
 * @param string $fn1 The first filename.
150
 * @param string $fn2 The second filename.
151
 * @return int Returns < 0 if $fn1 is less than $fn2; > 0 if $fn1 is greater than $fn2, and 0 if they are equal.
152
 *
153
 * @author Moisés Braga Ribeiro <[email protected]>
154
 */
155
function _sort_filenames_with_collator($fn1, $fn2) {
156
    $collator = _get_collator();
157
    return $collator->compare(utf8_decodeFN($fn1), utf8_decodeFN($fn2));
158
}
159
160
/**
161
 * Fallback string comparison for filenames, using strnatcasecmp().
162
 * The filenames are converted to page names with utf8_decodeFN() before the comparison.
163
 * 
164
 * @param string $fn1 The first filename.
165
 * @param string $fn2 The second filename.
166
 * @return int Returns < 0 if $fn1 is less than $fn2; > 0 if $fn1 is greater than $fn2, and 0 if they are equal.
167
 *
168
 * @author Moisés Braga Ribeiro <[email protected]>
169
 */
170
function _sort_filenames_without_collator($fn1, $fn2) {
171
    return strnatcasecmp(utf8_decodeFN($fn1), utf8_decodeFN($fn2));
172
}
173