Completed
Pull Request — master (#3115)
by
unknown
03:14
created

sort.php ➔ intl_sort()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 9
rs 9.9666
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
{
29
    global $conf;
30
    static $intl_extension_available = null;
31
    static $collator = null;
32
33
    if (is_null($intl_extension_available)) {
34
        $intl_extension_available = class_exists('Collator');
35
    }
36
    if (!$intl_extension_available) {
37
        return null;
38
    }
39
    if ($reload || !isset($collator)) {
40
        $collator = Collator::create($conf['lang']);
41
        if (isset($collator)) {
42
            $collator->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
43
            dbglog('Collator created with locale "' . $conf['lang'] . '": numeric collation on, ' .
44
                   'valid locale "' . $collator->getLocale(Locale::VALID_LOCALE) . '", ' .
45
                   'actual locale "' . $collator->getLocale(Locale::ACTUAL_LOCALE) . '"');
46
        }
47
    }
48
    return $collator;
49
}
50
51
/**
52
 * When $conf['lang'] is changed, this function should be called to re-create the collator
53
 * using the new value.
54
 *
55
 * @author Moisés Braga Ribeiro <[email protected]>
56
 */
57
function lang_has_changed()
58
{
59
    _get_collator(true);
60
}
61
62
/**
63
 * Drop-in replacement for strcmp(), strcasecmp(), strnatcmp() and strnatcasecmp().
64
 * It uses a collator-based comparison, or strnatcasecmp() as a fallback.
65
 *
66
 * @param string $str1 The first string.
67
 * @param string $str2 The second string.
68
 * @return int Returns < 0 if $str1 is less than $str2; > 0 if $str1 is greater than $str2, and 0 if they are equal.
69
 *
70
 * @author Moisés Braga Ribeiro <[email protected]>
71
 */
72
function intl_strcmp($str1, $str2)
73
{
74
    $collator = _get_collator();
75
    if (isset($collator)) {
76
        return $collator->compare($str1, $str2);
77
    } else {
78
        return strnatcasecmp($str1, $str2);
79
    }
80
}
81
82
/**
83
 * Drop-in replacement for sort().
84
 * It uses a collator-based sort, or sort() with flags SORT_NATURAL and SORT_FLAG_CASE as a fallback.
85
 *
86
 * @param array $array The input array.
87
 * @return bool Returns true on success or false on failure.
88
 *
89
 * @author Moisés Braga Ribeiro <[email protected]>
90
 */
91
function intl_sort(&$array)
92
{
93
    $collator = _get_collator();
94
    if (isset($collator)) {
95
        return $collator->sort($array);
96
    } else {
97
        return sort($array, SORT_NATURAL | SORT_FLAG_CASE);
98
    }
99
}
100
101
/**
102
 * Drop-in replacement for ksort().
103
 * It uses a collator-based sort, or ksort() with flags SORT_NATURAL and SORT_FLAG_CASE as a fallback.
104
 *
105
 * @param array $array The input array.
106
 * @return bool Returns true on success or false on failure.
107
 *
108
 * @author Moisés Braga Ribeiro <[email protected]>
109
 */
110
function intl_ksort(&$array)
111
{
112
    $collator = _get_collator();
113
    if (isset($collator)) {
114
        return uksort($array, array($collator, 'compare'));
115
    } else {
116
        return ksort($array, SORT_NATURAL | SORT_FLAG_CASE);
117
    }
118
}
119
120
/**
121
 * Drop-in replacement for asort(), natsort() and natcasesort().
122
 * It uses a collator-based sort, or asort() with flags SORT_NATURAL and SORT_FLAG_CASE as a fallback.
123
 *
124
 * @param array $array The input array.
125
 * @return bool Returns true on success or false on failure.
126
 *
127
 * @author Moisés Braga Ribeiro <[email protected]>
128
 */
129
function intl_asort(&$array)
130
{
131
    $collator = _get_collator();
132
    if (isset($collator)) {
133
        return $collator->asort($array);
134
    } else {
135
        return asort($array, SORT_NATURAL | SORT_FLAG_CASE);
136
    }
137
}
138
139
/**
140
 * Drop-in replacement for asort(), natsort() and natcasesort() when the parameter is an array of filenames.
141
 * Filenames may not be equal to page names, depending on the setting in $conf['fnencode'],
142
 * so the correct behavior is to sort page names and reflect this sorting in the filename array.
143
 *
144
 * @param array $array The input array.
145
 * @return bool Returns true on success or false on failure.
146
 *
147
 * @author Moisés Braga Ribeiro <[email protected]>
148
 */
149
function intl_asortFN(&$array)
150
{
151
    $collator = _get_collator();
152
    if (isset($collator)) {
153
        return uasort($array, '_sort_filenames_with_collator');
154
    } else {
155
        return uasort($array, '_sort_filenames_without_collator');
156
    }
157
}
158
159
/**
160
 * Collator-based string comparison for filenames.
161
 * The filenames are converted to page names with utf8_decodeFN() before the comparison.
162
 * 
163
 * @param string $fn1 The first filename.
164
 * @param string $fn2 The second filename.
165
 * @return int Returns < 0 if $fn1 is less than $fn2; > 0 if $fn1 is greater than $fn2, and 0 if they are equal.
166
 *
167
 * @author Moisés Braga Ribeiro <[email protected]>
168
 */
169
function _sort_filenames_with_collator($fn1, $fn2)
170
{
171
    $collator = _get_collator();
172
    return $collator->compare(utf8_decodeFN($fn1), utf8_decodeFN($fn2));
173
}
174
175
/**
176
 * Fallback string comparison for filenames, using strnatcasecmp().
177
 * The filenames are converted to page names with utf8_decodeFN() before the comparison.
178
 * 
179
 * @param string $fn1 The first filename.
180
 * @param string $fn2 The second filename.
181
 * @return int Returns < 0 if $fn1 is less than $fn2; > 0 if $fn1 is greater than $fn2, and 0 if they are equal.
182
 *
183
 * @author Moisés Braga Ribeiro <[email protected]>
184
 */
185
function _sort_filenames_without_collator($fn1, $fn2)
186
{
187
    return strnatcasecmp(utf8_decodeFN($fn1), utf8_decodeFN($fn2));
188
}
189