1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* TNumberFromat component. |
4
|
|
|
* |
5
|
|
|
* @author Wei Zhuo <weizhuo[at]gmail[dot]com> |
6
|
|
|
* @link https://github.com/pradosoft/prado |
7
|
|
|
* @copyright Copyright © 2005-2016 The PRADO Group |
8
|
|
|
* @license https://github.com/pradosoft/prado/blob/master/LICENSE |
9
|
|
|
* @package Prado\I18N |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Prado\I18N; |
13
|
|
|
|
14
|
|
|
use Prado\Exceptions\TInvalidDataValueException; |
15
|
|
|
use Prado\Prado; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Get the parent control class. |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* To format numbers in locale sensitive manner use |
23
|
|
|
* <code> |
24
|
|
|
* <com:TNumberFormat Pattern="0.##" value="2.0" /> |
25
|
|
|
* </code> |
26
|
|
|
* |
27
|
|
|
* The format used for numbers can be selected by specifying the Type attribute. |
28
|
|
|
* The known types are "decimal", "currency", "percentage", "scientific", |
29
|
|
|
* "spellout", "ordinal" and "duration" |
30
|
|
|
* |
31
|
|
|
* If someone from US want to see sales figures from a store in |
32
|
|
|
* Germany (say using the EURO currency), formatted using the german |
33
|
|
|
* currency, you would need to use the attribute Culture="de_DE" to get |
34
|
|
|
* the currency right, e.g. 100,00. The decimal and grouping separator is |
35
|
|
|
* then also from the de_DE locale. This may lead to some confusion because |
36
|
|
|
* people from US know the "," as thousand separator. Therefore a "Currency" |
37
|
|
|
* attribute is available, so that the output from the following example |
38
|
|
|
* results in 100.00. |
39
|
|
|
* <code> |
40
|
|
|
* <com:TNumberFormat Type="currency" Culture="en_US" Currency="EUR" Value="100" /> |
41
|
|
|
* </code> |
42
|
|
|
* |
43
|
|
|
* @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com> |
44
|
|
|
* @author Fabio Bas <ctrlaltca[at]gmail[dot]com> |
45
|
|
|
* @package Prado\I18N |
46
|
|
|
*/ |
47
|
|
|
class TNumberFormat extends TI18NControl implements \Prado\IDataRenderer |
48
|
|
|
{ |
49
|
|
|
/** |
50
|
|
|
* Cached NumberFormatters set to the application culture. |
51
|
|
|
* @var NumberFormat |
52
|
|
|
*/ |
53
|
|
|
protected static $formatters; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Get the number formatting pattern. |
57
|
|
|
* @return string format pattern. |
58
|
|
|
*/ |
59
|
|
|
public function getPattern() |
60
|
|
|
{ |
61
|
|
|
return $this->getViewState('Pattern', ''); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Set the number format pattern. |
66
|
|
|
* @param string $pattern format pattern. |
67
|
|
|
*/ |
68
|
|
|
public function setPattern($pattern) |
69
|
|
|
{ |
70
|
|
|
$this->setViewState('Pattern', $pattern, ''); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Get the numberic value for this control. |
75
|
|
|
* @return string number |
76
|
|
|
*/ |
77
|
|
|
public function getValue() |
78
|
|
|
{ |
79
|
|
|
return $this->getViewState('Value', ''); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Set the numberic value for this control. |
84
|
|
|
* @param string $value the number value |
85
|
|
|
*/ |
86
|
|
|
public function setValue($value) |
87
|
|
|
{ |
88
|
|
|
$this->setViewState('Value', $value, ''); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Get the default text value for this control. |
93
|
|
|
* @return string default text value |
94
|
|
|
*/ |
95
|
|
|
public function getDefaultText() |
96
|
|
|
{ |
97
|
|
|
return $this->getViewState('DefaultText', ''); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Set the default text value for this control. |
102
|
|
|
* @param string $value default text value |
103
|
|
|
*/ |
104
|
|
|
public function setDefaultText($value) |
105
|
|
|
{ |
106
|
|
|
$this->setViewState('DefaultText', $value, ''); |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Get the numberic value for this control. |
111
|
|
|
* This method is required by {@link \Prado\IDataRenderer}. |
112
|
|
|
* It is the same as {@link getValue()}. |
113
|
|
|
* @return string number |
114
|
|
|
* @see getValue |
115
|
|
|
* @since 3.1.2 |
116
|
|
|
*/ |
117
|
|
|
public function getData() |
118
|
|
|
{ |
119
|
|
|
return $this->getValue(); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Set the numberic value for this control. |
124
|
|
|
* This method is required by {@link \Prado\IDataRenderer}. |
125
|
|
|
* It is the same as {@link setValue()}. |
126
|
|
|
* @param string $value the number value |
127
|
|
|
* @see setValue |
128
|
|
|
* @since 3.1.2 |
129
|
|
|
*/ |
130
|
|
|
public function setData($value) |
131
|
|
|
{ |
132
|
|
|
$this->setValue($value); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Get the formatting type for this control. |
137
|
|
|
* @return string formatting type. |
138
|
|
|
*/ |
139
|
|
|
public function getType() |
140
|
|
|
{ |
141
|
|
|
return $this->getViewState('Type', \NumberFormatter::DECIMAL); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Set the formatting type for this control. |
146
|
|
|
* @param string $type formatting type, either "decimal", "currency", "percentage", "scientific", "spellout", "ordinal" or "duration" |
147
|
|
|
* @throws TPropertyTypeInvalidException |
148
|
|
|
*/ |
149
|
|
|
public function setType($type) |
150
|
|
|
{ |
151
|
|
|
$type = strtolower($type); |
152
|
|
|
|
153
|
|
|
switch ($type) { |
154
|
|
|
case 'decimal': |
155
|
|
|
$this->setViewState('Type', \NumberFormatter::DECIMAL); break; |
156
|
|
|
case 'currency': |
157
|
|
|
$this->setViewState('Type', \NumberFormatter::CURRENCY); break; |
158
|
|
|
case 'percentage': |
159
|
|
|
$this->setViewState('Type', \NumberFormatter::PERCENT); break; |
160
|
|
|
case 'scientific': |
161
|
|
|
$this->setViewState('Type', \NumberFormatter::SCIENTIFIC); break; |
162
|
|
|
case 'spellout': |
163
|
|
|
$this->setViewState('Type', \NumberFormatter::SPELLOUT); break; |
164
|
|
|
case 'ordinal': |
165
|
|
|
$this->setViewState('Type', \NumberFormatter::ORDINAL); break; |
166
|
|
|
case 'duration': |
167
|
|
|
$this->setViewState('Type', \NumberFormatter::DURATION); break; |
168
|
|
|
default: |
169
|
|
|
throw new TInvalidDataValueException('numberformat_type_invalid', $type); |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @return string 3 letter currency code. Defaults to 'USD'. |
175
|
|
|
*/ |
176
|
|
|
public function getCurrency() |
177
|
|
|
{ |
178
|
|
|
return $this->getViewState('Currency', 'USD'); |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Set the 3-letter ISO 4217 code. For example, the code |
183
|
|
|
* "USD" represents the US Dollar and "EUR" represents the Euro currency. |
184
|
|
|
* @param string $currency currency code. |
185
|
|
|
*/ |
186
|
|
|
public function setCurrency($currency) |
187
|
|
|
{ |
188
|
|
|
$this->setViewState('Currency', $currency, ''); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Formats the localized number, be it currency or decimal, or percentage. |
193
|
|
|
* If the culture is not specified, the default application |
194
|
|
|
* culture will be used. |
195
|
|
|
* @param string $culture |
196
|
|
|
* @param string $type |
197
|
|
|
* @return NumberFormatter |
198
|
|
|
*/ |
199
|
|
|
protected function getFormatter($culture, $type) |
200
|
|
|
{ |
201
|
|
|
if(!isset(self::$formatters[$culture])) |
202
|
|
|
self::$formatters[$culture] = []; |
203
|
|
|
if(!isset(self::$formatters[$culture][$type])) |
204
|
|
|
self::$formatters[$culture][$type] = new \NumberFormatter($culture, $type); |
205
|
|
|
|
206
|
|
|
return self::$formatters[$culture][$type]; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Formats the localized number, be it currency or decimal, or percentage. |
211
|
|
|
* If the culture is not specified, the default application |
212
|
|
|
* culture will be used. |
213
|
|
|
* @return string formatted number |
214
|
|
|
*/ |
215
|
|
|
protected function getFormattedValue() |
216
|
|
|
{ |
217
|
|
|
$value = $this->getValue(); |
218
|
|
|
$defaultText = $this->getDefaultText(); |
219
|
|
|
if (empty($value) && !empty($defaultText)) { |
220
|
|
|
return $this->getDefaultText(); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
$culture = $this->getCulture(); |
224
|
|
|
$type = $this->getType(); |
225
|
|
|
$pattern = $this->getPattern(); |
226
|
|
|
|
227
|
|
|
if(empty($pattern)) |
228
|
|
|
{ |
229
|
|
|
$formatter = $this->getFormatter($culture, $type); |
230
|
|
|
} else { |
231
|
|
|
$formatter = new \NumberFormatter($culture, \NumberFormatter::PATTERN_DECIMAL); |
232
|
|
|
$formatter->setPattern($pattern); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
if($type === \NumberFormatter::CURRENCY) |
236
|
|
|
{ |
237
|
|
|
$result = $formatter->formatCurrency($this->getValue(), $this->getCurrency()); |
238
|
|
|
} else { |
239
|
|
|
$result = $formatter->format($this->getValue()); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
return $this->I18N_toEncoding($result, $this->getCharset()); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
public function render($writer) |
246
|
|
|
{ |
247
|
|
|
$writer->write($this->getFormattedValue()); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Convert UTF-8 strings to a different encoding. NB. The result |
252
|
|
|
* may not have been encoded if iconv fails. |
253
|
|
|
* @param string $string the UTF-8 string for conversion |
254
|
|
|
* @param string $to detination encoding |
255
|
|
|
* @return string encoded string. |
256
|
|
|
*/ |
257
|
|
View Code Duplication |
protected function I18N_toEncoding($string, $to) |
|
|
|
|
258
|
|
|
{ |
259
|
|
|
if ($to != 'UTF-8') { |
260
|
|
|
$s = iconv('UTF-8', $to, $string); |
261
|
|
|
return $s !== false ? $s : $string; |
262
|
|
|
} |
263
|
|
|
return $string; |
264
|
|
|
} |
265
|
|
|
} |
266
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.