1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
use SMW\DataValues\ValueFormatters\DataValueFormatter; |
4
|
|
|
use SMW\IntlNumberFormatter; |
5
|
|
|
use SMW\Localizer; |
6
|
|
|
use SMW\Message; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* @ingroup SMWDataValues |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* This datavalue implements numerical datavalues, and supports optional |
14
|
|
|
* unit conversions. It parses and manages unit strings, since even plain |
15
|
|
|
* numbers may have (not further specified) units that are stored. However, |
16
|
|
|
* only subclasses implement full unit conversion by extending the methods |
17
|
|
|
* convertToMainUnit() and makeConversionValues(). |
18
|
|
|
* |
19
|
|
|
* Units work as follows: a unit is a string, but many such strings might |
20
|
|
|
* refer to the same unit of measurement. There is always one string, that |
21
|
|
|
* canonically represents the unit, and we will call this version of writing |
22
|
|
|
* the unit the /unit id/. IDs for units are needed for tasks like duplicate |
23
|
|
|
* avoidance. If no conversion information is given, any unit is its own ID. |
24
|
|
|
* In any case, units are /normalised/, i.e. given a more standardised meaning |
25
|
|
|
* before being processed. All units, IDs or otherwise, should be suitable for |
26
|
|
|
* printout in wikitext, and main IDs should moreover be suitable for printout |
27
|
|
|
* in HTML. |
28
|
|
|
* |
29
|
|
|
* Subclasses that support unit conversion may interpret the output format set |
30
|
|
|
* via setOutputFormat() to allow a unit to be selected for display. Note that |
31
|
|
|
* this setting does not affect the internal representation of the value |
32
|
|
|
* though. So chosing a specific output format will change the behavior of |
33
|
|
|
* output functions like getLongWikiText(), but not of functions that access |
34
|
|
|
* the value itself, such as getUnit() or getDBKeys(). |
35
|
|
|
* |
36
|
|
|
* @author Markus Krötzsch |
37
|
|
|
* @ingroup SMWDataValues |
38
|
|
|
* |
39
|
|
|
* @todo Wiki-HTML-conversion for unit strings must be revisited, as the current |
40
|
|
|
* solution might be unsafe. |
41
|
|
|
*/ |
42
|
|
|
class SMWNumberValue extends SMWDataValue { |
|
|
|
|
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Array with entries unit=>value, mapping a normalized unit to the |
46
|
|
|
* converted value. Used for conversion tooltips. |
47
|
|
|
* @var array |
48
|
|
|
*/ |
49
|
|
|
protected $m_unitvalues; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Whether the unit is preferred as prefix or not |
53
|
|
|
* |
54
|
|
|
* @var array |
55
|
|
|
*/ |
56
|
|
|
protected $prefixalUnitPreference = array(); |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Canonical identifier for the unit that the user gave as input. Used |
60
|
|
|
* to avoid printing this in conversion tooltips again. If the |
61
|
|
|
* outputformat was set to show another unit, then the values of |
62
|
|
|
* $m_caption and $m_unitin will be updated as if the formatted string |
63
|
|
|
* had been the original user input, i.e. the two values reflect what |
64
|
|
|
* is currently printed. |
65
|
|
|
* @var string |
66
|
|
|
*/ |
67
|
|
|
protected $m_unitin; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @var integer|null |
71
|
|
|
*/ |
72
|
|
|
protected $precision = null; |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* @var IntlNumberFormatter |
76
|
|
|
*/ |
77
|
|
|
private $intlNumberFormatter = null; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* @since 2.4 |
81
|
|
|
* |
82
|
|
|
* @param string $typeid |
83
|
|
|
*/ |
84
|
49 |
|
public function __construct( $typeid = '' ) { |
85
|
49 |
|
parent::__construct( $typeid ); |
86
|
49 |
|
$this->intlNumberFormatter = IntlNumberFormatter::getInstance(); |
87
|
49 |
|
$this->intlNumberFormatter->initialize(); |
88
|
49 |
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Parse a string of the form "number unit" where unit is optional. The |
92
|
|
|
* results are stored in the $number and $unit parameters. Returns an |
93
|
|
|
* error code. |
94
|
|
|
* @param $value string to parse |
95
|
|
|
* @param $number call-by-ref parameter that will be set to the numerical value |
96
|
|
|
* @param $unit call-by-ref parameter that will be set to the "unit" string (after the number) |
97
|
|
|
* @return integer 0 (no errors), 1 (no number found at all), 2 (number |
98
|
|
|
* too large for this platform) |
99
|
|
|
*/ |
100
|
47 |
|
public function parseNumberValue( $value, &$number, &$unit, &$asPrefix = false ) { |
101
|
|
|
|
102
|
47 |
|
$intlNumberFormatter = $this->getNumberFormatter(); |
103
|
|
|
|
104
|
|
|
// Parse to find $number and (possibly) $unit |
105
|
47 |
|
$kiloseparator = $intlNumberFormatter->getSeparator( |
106
|
47 |
|
IntlNumberFormatter::THOUSANDS_SEPARATOR, |
107
|
47 |
|
IntlNumberFormatter::CONTENT_LANGUAGE |
108
|
|
|
); |
109
|
|
|
|
110
|
47 |
|
$decseparator = $intlNumberFormatter->getSeparator( |
111
|
47 |
|
IntlNumberFormatter::DECIMAL_SEPARATOR, |
112
|
47 |
|
IntlNumberFormatter::CONTENT_LANGUAGE |
113
|
|
|
); |
114
|
|
|
|
115
|
|
|
// #753 |
116
|
|
|
$regex = '/([-+]?\s*(?:' . |
117
|
|
|
// Either numbers like 10,000.99 that start with a digit |
118
|
47 |
|
'\d+(?:\\' . $kiloseparator . '\d\d\d)*(?:\\' . $decseparator . '\d+)?' . |
119
|
|
|
// or numbers like .001 that start with the decimal separator |
120
|
47 |
|
'|\\' . $decseparator . '\d+' . |
121
|
47 |
|
')\s*(?:[eE][-+]?\d+)?)/u'; |
122
|
|
|
|
123
|
47 |
|
$parts = preg_split( |
124
|
|
|
$regex, |
125
|
47 |
|
trim( str_replace( array( ' ', ' ', ' ', ' ' ), '', $value ) ), |
126
|
47 |
|
2, |
127
|
47 |
|
PREG_SPLIT_DELIM_CAPTURE |
128
|
|
|
); |
129
|
|
|
|
130
|
47 |
|
if ( count( $parts ) >= 2 ) { |
131
|
47 |
|
$numstring = str_replace( $kiloseparator, '', preg_replace( '/\s*/u', '', $parts[1] ) ); // simplify |
132
|
47 |
|
if ( $decseparator != '.' ) { |
133
|
3 |
|
$numstring = str_replace( $decseparator, '.', $numstring ); |
134
|
|
|
} |
135
|
47 |
|
list( $number ) = sscanf( $numstring, "%f" ); |
136
|
47 |
|
if ( count( $parts ) >= 3 ) { |
137
|
47 |
|
$asPrefix = $parts[0] !== ''; |
138
|
47 |
|
$unit = $this->normalizeUnit( $parts[0] !== '' ? $parts[0] : $parts[2] ); |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
|
142
|
47 |
|
if ( ( count( $parts ) == 1 ) || ( $numstring === '' ) ) { // no number found |
|
|
|
|
143
|
1 |
|
return 1; |
144
|
47 |
|
} elseif ( is_infinite( $number ) ) { // number is too large for this platform |
145
|
|
|
return 2; |
146
|
|
|
} else { |
147
|
47 |
|
return 0; |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* @see DataValue::parseUserValue |
153
|
|
|
*/ |
154
|
48 |
|
protected function parseUserValue( $value ) { |
155
|
|
|
// Set caption |
156
|
48 |
|
if ( $this->m_caption === false ) { |
157
|
48 |
|
$this->m_caption = $value; |
158
|
|
|
} |
159
|
|
|
|
160
|
48 |
|
if ( $value !== '' && $value{0} === ':' ) { |
161
|
1 |
|
$this->addErrorMsg( array( 'smw-datavalue-invalid-number', $value ) ); |
162
|
1 |
|
return; |
163
|
|
|
} |
164
|
|
|
|
165
|
47 |
|
$this->m_unitin = false; |
|
|
|
|
166
|
47 |
|
$this->m_unitvalues = false; |
|
|
|
|
167
|
47 |
|
$number = $unit = ''; |
168
|
47 |
|
$error = $this->parseNumberValue( $value, $number, $unit ); |
169
|
|
|
|
170
|
47 |
|
if ( $error == 1 ) { // no number found |
171
|
1 |
|
$this->addErrorMsg( array( 'smw_nofloat', $value ) ); |
172
|
47 |
|
} elseif ( $error == 2 ) { // number is too large for this platform |
173
|
|
|
$this->addErrorMsg( array( 'smw_infinite', $value ) ); |
174
|
47 |
|
} elseif ( $this->getTypeID() === '_num' && $unit !== '' ) { |
175
|
1 |
|
$this->addErrorMsg( array( 'smw-datavalue-number-textnotallowed', $unit, $number ) ); |
176
|
47 |
|
} elseif ( $number === null ) { |
177
|
|
|
$this->addErrorMsg( array( 'smw-datavalue-number-nullnotallowed', $value ) ); // #1628 |
178
|
47 |
|
} elseif ( $this->convertToMainUnit( $number, $unit ) === false ) { // so far so good: now convert unit and check if it is allowed |
179
|
9 |
|
$this->addErrorMsg( array( 'smw_unitnotallowed', $unit ) ); |
180
|
|
|
} // note that convertToMainUnit() also sets m_dataitem if valid |
181
|
47 |
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* @see SMWDataValue::loadDataItem() |
185
|
|
|
* @param $dataitem SMWDataItem |
186
|
|
|
* @return boolean |
187
|
|
|
*/ |
188
|
28 |
|
protected function loadDataItem( SMWDataItem $dataItem ) { |
189
|
|
|
|
190
|
28 |
|
if ( $dataItem->getDIType() !== SMWDataItem::TYPE_NUMBER ) { |
191
|
|
|
return false; |
192
|
|
|
} |
193
|
|
|
|
194
|
28 |
|
$this->m_dataitem = $dataItem; |
195
|
28 |
|
$this->m_caption = false; |
|
|
|
|
196
|
28 |
|
$this->m_unitin = false; |
|
|
|
|
197
|
28 |
|
$this->makeUserValue(); |
198
|
28 |
|
$this->m_unitvalues = false; |
|
|
|
|
199
|
|
|
|
200
|
28 |
|
return true; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* @see DataValue::setOutputFormat |
205
|
|
|
* |
206
|
|
|
* @param $string $formatstring |
|
|
|
|
207
|
|
|
*/ |
208
|
8 |
|
public function setOutputFormat( $formatstring ) { |
209
|
|
|
|
210
|
8 |
|
if ( $formatstring == $this->m_outformat ) { |
211
|
|
|
return null; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
// #1591 |
215
|
8 |
|
$this->findPreferredLanguageFrom( $formatstring ); |
216
|
|
|
|
217
|
|
|
// #1335 |
218
|
8 |
|
$this->m_outformat = $this->findPrecisionFrom( $formatstring ); |
219
|
|
|
|
220
|
8 |
|
if ( $this->isValid() ) { // update caption/unitin for this format |
221
|
8 |
|
$this->m_caption = false; |
|
|
|
|
222
|
8 |
|
$this->m_unitin = false; |
|
|
|
|
223
|
8 |
|
$this->makeUserValue(); |
224
|
|
|
} |
225
|
8 |
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* @since 2.4 |
229
|
|
|
* |
230
|
|
|
* @return float |
231
|
|
|
*/ |
232
|
35 |
|
public function getLocalizedFormattedNumber( $value ) { |
233
|
35 |
|
return $this->getNumberFormatter()->format( $value, $this->getPreferredDisplayPrecision() ); |
|
|
|
|
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @since 2.4 |
238
|
|
|
* |
239
|
|
|
* @return float |
240
|
|
|
*/ |
241
|
16 |
|
public function getNormalizedFormattedNumber( $value ) { |
242
|
16 |
|
return $this->getNumberFormatter()->format( $value, $this->getPreferredDisplayPrecision(), IntlNumberFormatter::VALUE_FORMAT ); |
|
|
|
|
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* @see DataValue::getShortWikiText |
247
|
|
|
* |
248
|
|
|
* @return string |
249
|
|
|
*/ |
250
|
33 |
|
public function getShortWikiText( $linker = null ) { |
251
|
33 |
|
return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_SHORT, $linker ); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* @see DataValue::getShortHTMLText |
256
|
|
|
* |
257
|
|
|
* @return string |
258
|
|
|
*/ |
259
|
1 |
|
public function getShortHTMLText( $linker = null ) { |
260
|
1 |
|
return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_SHORT, $linker ); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* @see DataValue::getLongWikiText |
265
|
|
|
* |
266
|
|
|
* @return string |
267
|
|
|
*/ |
268
|
|
|
public function getLongWikiText( $linker = null ) { |
269
|
|
|
return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_LONG, $linker ); |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* @see DataValue::getLongHTMLText |
274
|
|
|
* |
275
|
|
|
* @return string |
276
|
|
|
*/ |
277
|
2 |
|
public function getLongHTMLText( $linker = null ) { |
278
|
2 |
|
return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_LONG, $linker ); |
279
|
|
|
} |
280
|
|
|
|
281
|
20 |
|
public function getNumber() { |
282
|
20 |
|
return $this->isValid() ? $this->m_dataitem->getNumber() : 32202; |
|
|
|
|
283
|
|
|
} |
284
|
|
|
|
285
|
13 |
|
public function getWikiValue() { |
286
|
13 |
|
return $this->getDataValueFormatter()->format( DataValueFormatter::VALUE ); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* @see DataVelue::getInfolinks |
291
|
|
|
* |
292
|
|
|
* @return array |
293
|
|
|
*/ |
294
|
1 |
|
public function getInfolinks() { |
295
|
|
|
|
296
|
|
|
// When generating an infoLink, use the normalized value without any |
297
|
|
|
// precision limitation |
298
|
1 |
|
$this->setOption( 'no.displayprecision', true ); |
|
|
|
|
299
|
1 |
|
$this->setOption( 'content.language', Message::CONTENT_LANGUAGE ); |
300
|
1 |
|
$infoLinks = parent::getInfolinks(); |
301
|
1 |
|
$this->setOption( 'no.displayprecision', false ); |
|
|
|
|
302
|
|
|
|
303
|
1 |
|
return $infoLinks; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* @since 2.4 |
308
|
|
|
* |
309
|
|
|
* @return string |
310
|
|
|
*/ |
311
|
31 |
|
public function getCanonicalMainUnit() { |
312
|
31 |
|
return $this->m_unitin; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* Returns array of converted unit-value-pairs that can be |
317
|
|
|
* printed. |
318
|
|
|
* |
319
|
|
|
* @since 2.4 |
320
|
|
|
* |
321
|
|
|
* @return array |
322
|
|
|
*/ |
323
|
31 |
|
public function getConvertedUnitValues() { |
324
|
31 |
|
$this->makeConversionValues(); |
325
|
31 |
|
return $this->m_unitvalues; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* Return the unit in which the returned value is to be interpreted. |
330
|
|
|
* This string is a plain UTF-8 string without wiki or html markup. |
331
|
|
|
* The returned value is a canonical ID for the main unit. |
332
|
|
|
* Returns the empty string if no unit is given for the value. |
333
|
|
|
* Overwritten by subclasses that support units. |
334
|
|
|
*/ |
335
|
10 |
|
public function getUnit() { |
336
|
10 |
|
return ''; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* @since 2.4 |
341
|
|
|
* |
342
|
|
|
* @param string $unit |
343
|
|
|
* |
344
|
|
|
* @return boolean |
345
|
|
|
*/ |
346
|
16 |
|
public function hasPrefixalUnitPreference( $unit ) { |
347
|
16 |
|
return isset( $this->prefixalUnitPreference[$unit] ) && $this->prefixalUnitPreference[$unit]; |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* Create links to mapping services based on a wiki-editable message. |
352
|
|
|
* The parameters available to the message are: |
353
|
|
|
* $1: string of numerical value in English punctuation |
354
|
|
|
* $2: string of integer version of value, in English punctuation |
355
|
|
|
* |
356
|
|
|
* @return array |
357
|
|
|
*/ |
358
|
1 |
|
protected function getServiceLinkParams() { |
359
|
1 |
|
if ( $this->isValid() ) { |
360
|
1 |
|
return array( strval( $this->m_dataitem->getNumber() ), strval( round( $this->m_dataitem->getNumber() ) ) ); |
|
|
|
|
361
|
|
|
} else { |
362
|
|
|
return array(); |
|
|
|
|
363
|
|
|
} |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* Transform a (typically unit-) string into a normalised form, |
368
|
|
|
* so that, e.g., "km²" and "km<sup>2</sup>" do not need to be |
369
|
|
|
* distinguished. |
370
|
|
|
*/ |
371
|
47 |
|
public function normalizeUnit( $unit ) { |
372
|
47 |
|
$unit = str_replace( array( '[[', ']]' ), '', trim( $unit ) ); // allow simple links to be used inside annotations |
373
|
47 |
|
$unit = str_replace( array( '²', '<sup>2</sup>' ), '²', $unit ); |
374
|
47 |
|
$unit = str_replace( array( '³', '<sup>3</sup>' ), '³', $unit ); |
375
|
47 |
|
return smwfXMLContentEncode( $unit ); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Compute the value based on the given input number and unit string. |
380
|
|
|
* If the unit is not supported, return false, otherwise return true. |
381
|
|
|
* This is called when parsing user input, where the given unit value |
382
|
|
|
* has already been normalized. |
383
|
|
|
* |
384
|
|
|
* This class does not support any (non-empty) units, but subclasses |
385
|
|
|
* may overwrite this behavior. |
386
|
|
|
* @param $number float value obtained by parsing user input |
387
|
|
|
* @param $unit string after the numericla user input |
388
|
|
|
* @return boolean specifying if the unit string is allowed |
389
|
|
|
*/ |
390
|
37 |
|
protected function convertToMainUnit( $number, $unit ) { |
391
|
37 |
|
$this->m_dataitem = new SMWDINumber( $number ); |
392
|
37 |
|
$this->m_unitin = ''; |
393
|
37 |
|
return ( $unit === '' ); |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
/** |
397
|
|
|
* This method creates an array of unit-value-pairs that should be |
398
|
|
|
* printed. Units are the keys and should be canonical unit IDs. |
399
|
|
|
* The result is stored in $this->m_unitvalues. Again, any class that |
400
|
|
|
* requires effort for doing this should first check whether the array |
401
|
|
|
* is already set (i.e. not false) before doing any work. |
402
|
|
|
* Note that the values should be plain numbers. Output formatting is done |
403
|
|
|
* later when needed. Also, it should be checked if the value is valid |
404
|
|
|
* before trying to calculate with its contents. |
405
|
|
|
* This method also must call or implement convertToMainUnit(). |
406
|
|
|
* |
407
|
|
|
* Overwritten by subclasses that support units. |
408
|
|
|
*/ |
409
|
24 |
|
protected function makeConversionValues() { |
410
|
24 |
|
$this->m_unitvalues = array( '' => $this->m_dataitem->getNumber() ); |
|
|
|
|
411
|
24 |
|
} |
412
|
|
|
|
413
|
|
|
/** |
414
|
|
|
* This method is used when no user input was given to find the best |
415
|
|
|
* values for m_unitin and m_caption. After conversion, |
416
|
|
|
* these fields will look as if they were generated from user input, |
417
|
|
|
* and convertToMainUnit() will have been called (if not, it would be |
418
|
|
|
* blocked by the presence of m_unitin). |
419
|
|
|
* |
420
|
|
|
* Overwritten by subclasses that support units. |
421
|
|
|
*/ |
422
|
22 |
|
protected function makeUserValue() { |
423
|
22 |
|
$this->m_caption = ''; |
424
|
|
|
|
425
|
22 |
|
$number = $this->m_dataitem->getNumber(); |
|
|
|
|
426
|
|
|
|
427
|
|
|
// -u is the format for displaying the unit only |
428
|
22 |
|
if ( $this->m_outformat == '-u' ) { |
429
|
|
|
$this->m_caption = ''; |
430
|
22 |
|
} elseif ( ( $this->m_outformat != '-' ) && ( $this->m_outformat != '-n' ) ) { |
431
|
22 |
|
$this->m_caption = $this->getLocalizedFormattedNumber( $number ); |
432
|
|
|
} else { |
433
|
2 |
|
$this->m_caption = $this->getNormalizedFormattedNumber( $number ); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
// no unit ever, so nothing to do about this |
437
|
22 |
|
$this->m_unitin = ''; |
438
|
22 |
|
} |
439
|
|
|
|
440
|
|
|
/** |
441
|
|
|
* Return an array of major unit strings (ids only recommended) supported by |
442
|
|
|
* this datavalue. |
443
|
|
|
* |
444
|
|
|
* Overwritten by subclasses that support units. |
445
|
|
|
*/ |
446
|
|
|
public function getUnitList() { |
447
|
|
|
return array( '' ); |
448
|
|
|
} |
449
|
|
|
|
450
|
35 |
|
protected function getPreferredDisplayPrecision() { |
451
|
|
|
|
452
|
|
|
// In case of a value description, don't restrict the value with a display precision |
453
|
35 |
|
if ( $this->getProperty() === null || $this->getOptionValueFor( 'value.description' ) || $this->getOptionValueFor( 'no.displayprecision' ) ) { |
|
|
|
|
454
|
8 |
|
return false; |
455
|
|
|
} |
456
|
|
|
|
457
|
35 |
|
if ( $this->precision === null ) { |
458
|
35 |
|
$this->precision = $this->getPropertySpecificationLookup()->getDisplayPrecisionFor( |
|
|
|
|
459
|
35 |
|
$this->getProperty() |
460
|
|
|
); |
461
|
|
|
} |
462
|
|
|
|
463
|
35 |
|
return $this->precision; |
464
|
|
|
} |
465
|
|
|
|
466
|
8 |
|
private function findPrecisionFrom( $formatstring ) { |
467
|
|
|
|
468
|
8 |
|
if ( strpos( $formatstring, '-' ) === false ) { |
469
|
5 |
|
return $formatstring; |
470
|
|
|
} |
471
|
|
|
|
472
|
5 |
|
$parts = explode( '-', $formatstring ); |
473
|
|
|
|
474
|
|
|
// Find precision from annotated -p<number of digits> formatstring which |
475
|
|
|
// has priority over a possible _PREC value |
476
|
5 |
|
foreach ( $parts as $key => $value ) { |
477
|
5 |
|
if ( strpos( $value, 'p' ) !== false && is_numeric( substr( $value, 1 ) ) ) { |
478
|
2 |
|
$this->precision = strval( substr( $value, 1 ) ); |
|
|
|
|
479
|
5 |
|
unset( $parts[$key] ); |
480
|
|
|
} |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
// Rebuild formatstring without a possible p element to ensure other |
484
|
|
|
// options can be used in combination such as -n-p2 etc. |
485
|
5 |
|
return implode( '-', $parts ); |
486
|
|
|
} |
487
|
|
|
|
488
|
48 |
|
private function getNumberFormatter() { |
489
|
|
|
|
490
|
48 |
|
$this->intlNumberFormatter->setOption( |
491
|
48 |
|
'user.language', |
492
|
48 |
|
$this->getOptionValueFor( 'user.language' ) |
493
|
|
|
); |
494
|
|
|
|
495
|
48 |
|
$this->intlNumberFormatter->setOption( |
496
|
48 |
|
'content.language', |
497
|
48 |
|
$this->getOptionValueFor( 'content.language' ) |
498
|
|
|
); |
499
|
|
|
|
500
|
48 |
|
$this->intlNumberFormatter->setOption( |
501
|
48 |
|
'separator.thousands', |
502
|
48 |
|
$this->getOptionValueFor( 'separator.thousands' ) |
503
|
|
|
); |
504
|
|
|
|
505
|
48 |
|
$this->intlNumberFormatter->setOption( |
506
|
48 |
|
'separator.decimal', |
507
|
48 |
|
$this->getOptionValueFor( 'separator.decimal' ) |
508
|
|
|
); |
509
|
|
|
|
510
|
48 |
|
return $this->intlNumberFormatter; |
511
|
|
|
} |
512
|
|
|
|
513
|
8 |
|
private function findPreferredLanguageFrom( &$formatstring ) { |
514
|
|
|
// Localized preferred user language |
515
|
8 |
|
if ( strpos( $formatstring, 'LOCL' ) !== false && ( $languageCode = Localizer::getLanguageCodeFrom( $formatstring ) ) !== false ) { |
|
|
|
|
516
|
1 |
|
$this->intlNumberFormatter->setOption( |
517
|
1 |
|
'preferred.language', |
518
|
|
|
$languageCode |
519
|
|
|
); |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
// Remove any remaining |
523
|
8 |
|
$formatstring = str_replace( array( '#LOCL', 'LOCL' ), '', $formatstring ); |
524
|
8 |
|
} |
525
|
|
|
|
526
|
|
|
} |
527
|
|
|
|
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.