1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* Partially based on Zend_Currency. |
4
|
|
|
* |
5
|
|
|
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) |
6
|
|
|
* @license http://framework.zend.com/license/new-bsd New BSD License |
7
|
|
|
* @version $Id: Currency.php 6137 2007-08-19 14:55:27Z shreef $ |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
require_once 'Zend/Currency.php'; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Implements the "Money" pattern. |
14
|
|
|
* |
15
|
|
|
* @see http://www.martinfowler.com/eaaCatalog/money.html |
16
|
|
|
* |
17
|
|
|
* @todo Support different ways of rounding |
18
|
|
|
* @todo Equality operators |
19
|
|
|
* @todo Addition, substraction and allocation of values |
20
|
|
|
* @todo Model validation for $allowedCurrencies |
21
|
|
|
* |
22
|
|
|
* @package framework |
23
|
|
|
* @subpackage model |
24
|
|
|
*/ |
25
|
|
|
class Money extends DBField implements CompositeDBField { |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var string $getCurrency() |
29
|
|
|
*/ |
30
|
|
|
protected $currency; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var float $currencyAmount |
34
|
|
|
*/ |
35
|
|
|
protected $amount; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var boolean $isChanged |
39
|
|
|
*/ |
40
|
|
|
protected $isChanged = false; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var string $locale |
44
|
|
|
*/ |
45
|
|
|
protected $locale = null; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var Zend_Currency |
49
|
|
|
*/ |
50
|
|
|
protected $currencyLib; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Limit the currencies |
54
|
|
|
* @var array $allowedCurrencies |
55
|
|
|
*/ |
56
|
|
|
protected $allowedCurrencies; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @param array |
60
|
|
|
*/ |
61
|
|
|
private static $composite_db = array( |
62
|
|
|
"Currency" => "Varchar(3)", |
63
|
|
|
"Amount" => 'Decimal(19,4)' |
64
|
|
|
); |
65
|
|
|
|
66
|
|
|
public function __construct($name = null) { |
67
|
|
|
$this->currencyLib = new Zend_Currency(null, i18n::get_locale()); |
68
|
|
|
|
69
|
|
|
parent::__construct($name); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
public function compositeDatabaseFields() { |
73
|
|
|
return self::$composite_db; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
public function requireField() { |
77
|
|
|
$fields = $this->compositeDatabaseFields(); |
78
|
|
|
if($fields) foreach($fields as $name => $type){ |
|
|
|
|
79
|
|
|
DB::require_field($this->tableName, $this->name.$name, $type); |
80
|
|
|
} |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
public function writeToManipulation(&$manipulation) { |
84
|
|
|
if($this->getCurrency()) { |
85
|
|
|
$manipulation['fields'][$this->name.'Currency'] = $this->prepValueForDB($this->getCurrency()); |
86
|
|
|
} else { |
87
|
|
|
$manipulation['fields'][$this->name.'Currency'] |
88
|
|
|
= DBField::create_field('Varchar', $this->getCurrency())->nullValue(); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
if($this->getAmount()) { |
92
|
|
|
$manipulation['fields'][$this->name.'Amount'] = $this->getAmount(); |
93
|
|
|
} else { |
94
|
|
|
$manipulation['fields'][$this->name.'Amount'] |
95
|
|
|
= DBField::create_field('Decimal', $this->getAmount())->nullValue(); |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
public function addToQuery(&$query) { |
100
|
|
|
parent::addToQuery($query); |
101
|
|
|
$query->selectField(sprintf('"%sAmount"', $this->name)); |
102
|
|
|
$query->selectField(sprintf('"%sCurrency"', $this->name)); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
public function setValue($value, $record = null, $markChanged = true) { |
106
|
|
|
// Convert an object to an array |
107
|
|
|
if($record && $record instanceof DataObject) { |
108
|
|
|
$record = $record->getQueriedDatabaseFields(); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
// @todo Allow resetting value to NULL through Money $value field |
112
|
|
|
if ($value instanceof Money && $value->exists()) { |
113
|
|
|
$this->setCurrency($value->getCurrency(), $markChanged); |
114
|
|
|
$this->setAmount($value->getAmount(), $markChanged); |
115
|
|
|
if($markChanged) $this->isChanged = true; |
116
|
|
|
} else if($record && isset($record[$this->name . 'Amount'])) { |
117
|
|
|
if($record[$this->name . 'Amount']) { |
118
|
|
|
if(!empty($record[$this->name . 'Currency'])) { |
119
|
|
|
$this->setCurrency($record[$this->name . 'Currency'], $markChanged); |
120
|
|
|
} else if($currency = (string)$this->config()->default_currency) { |
121
|
|
|
$this->setCurrency($currency, $markChanged); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$this->setAmount($record[$this->name . 'Amount'], $markChanged); |
125
|
|
|
} else { |
126
|
|
|
$this->value = $this->nullValue(); |
127
|
|
|
} |
128
|
|
|
if($markChanged) $this->isChanged = true; |
129
|
|
|
} else if (is_array($value)) { |
130
|
|
|
if (array_key_exists('Currency', $value)) { |
131
|
|
|
$this->setCurrency($value['Currency'], $markChanged); |
132
|
|
|
} |
133
|
|
|
if (array_key_exists('Amount', $value)) { |
134
|
|
|
$this->setAmount($value['Amount'], $markChanged); |
135
|
|
|
} |
136
|
|
|
if($markChanged) $this->isChanged = true; |
137
|
|
|
} else { |
|
|
|
|
138
|
|
|
// @todo Allow to reset a money value by passing in NULL |
139
|
|
|
//user_error('Invalid value in Money->setValue()', E_USER_ERROR); |
|
|
|
|
140
|
|
|
} |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* @return string |
145
|
|
|
*/ |
146
|
|
|
public function Nice($options = array()) { |
147
|
|
|
$amount = $this->getAmount(); |
148
|
|
|
if(!isset($options['display'])) $options['display'] = Zend_Currency::USE_SYMBOL; |
149
|
|
|
if(!isset($options['currency'])) $options['currency'] = $this->getCurrency(); |
150
|
|
|
if(!isset($options['symbol'])) { |
151
|
|
|
$options['symbol'] = $this->currencyLib->getSymbol($this->getCurrency(), $this->getLocale()); |
152
|
|
|
} |
153
|
|
|
return (is_numeric($amount)) ? $this->currencyLib->toCurrency($amount, $options) : ''; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* @return string |
158
|
|
|
*/ |
159
|
|
|
public function NiceWithShortname($options = array()){ |
160
|
|
|
$options['display'] = Zend_Currency::USE_SHORTNAME; |
161
|
|
|
return $this->Nice($options); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @return string |
166
|
|
|
*/ |
167
|
|
|
public function NiceWithName($options = array()){ |
168
|
|
|
$options['display'] = Zend_Currency::USE_NAME; |
169
|
|
|
return $this->Nice($options); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @return string |
174
|
|
|
*/ |
175
|
|
|
public function getCurrency() { |
176
|
|
|
return $this->currency; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @param string |
181
|
|
|
*/ |
182
|
|
|
public function setCurrency($currency, $markChanged = true) { |
183
|
|
|
$this->currency = $currency; |
184
|
|
|
if($markChanged) $this->isChanged = true; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* @todo Return casted Float DBField? |
189
|
|
|
* |
190
|
|
|
* @return float |
191
|
|
|
*/ |
192
|
|
|
public function getAmount() { |
193
|
|
|
return $this->amount; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* @param float $amount |
198
|
|
|
*/ |
199
|
|
|
public function setAmount($amount, $markChanged = true) { |
200
|
|
|
$this->amount = (float)$amount; |
201
|
|
|
if($markChanged) $this->isChanged = true; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* @return boolean |
206
|
|
|
*/ |
207
|
|
|
public function exists() { |
208
|
|
|
return ($this->getCurrency() && is_numeric($this->getAmount())); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* @return boolean |
213
|
|
|
*/ |
214
|
|
|
public function hasAmount() { |
215
|
|
|
$a = $this->getAmount(); |
216
|
|
|
return (!empty($a) && is_numeric($a)); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
public function isChanged() { |
220
|
|
|
return $this->isChanged; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* @param string $locale |
225
|
|
|
*/ |
226
|
|
|
public function setLocale($locale) { |
227
|
|
|
$this->locale = $locale; |
228
|
|
|
$this->currencyLib->setLocale($locale); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* @return string |
233
|
|
|
*/ |
234
|
|
|
public function getLocale() { |
235
|
|
|
return ($this->locale) ? $this->locale : i18n::get_locale(); |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* @return string |
240
|
|
|
*/ |
241
|
|
|
public function getSymbol($currency = null, $locale = null) { |
242
|
|
|
|
243
|
|
|
if($locale === null) $locale = $this->getLocale(); |
244
|
|
|
if($currency === null) $currency = $this->getCurrency(); |
245
|
|
|
|
246
|
|
|
return $this->currencyLib->getSymbol($currency, $locale); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* @return string |
251
|
|
|
*/ |
252
|
|
|
public function getShortName($currency = null, $locale = null) { |
253
|
|
|
if($locale === null) $locale = $this->getLocale(); |
254
|
|
|
if($currency === null) $currency = $this->getCurrency(); |
255
|
|
|
|
256
|
|
|
return $this->currencyLib->getShortName($currency, $locale); |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* @return string |
261
|
|
|
*/ |
262
|
|
|
public function getName($currency = null, $locale = null) { |
263
|
|
|
if($locale === null) $locale = $this->getLocale(); |
264
|
|
|
if($currency === null) $currency = $this->getCurrency(); |
265
|
|
|
|
266
|
|
|
return $this->currencyLib->getName($currency, $locale); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
/** |
270
|
|
|
* @param array $arr |
271
|
|
|
*/ |
272
|
|
|
public function setAllowedCurrencies($arr) { |
273
|
|
|
$this->allowedCurrencies = $arr; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* @return array |
278
|
|
|
*/ |
279
|
|
|
public function getAllowedCurrencies() { |
280
|
|
|
return $this->allowedCurrencies; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Returns a CompositeField instance used as a default |
285
|
|
|
* for form scaffolding. |
286
|
|
|
* |
287
|
|
|
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()} |
288
|
|
|
* |
289
|
|
|
* @param string $title Optional. Localized title of the generated instance |
290
|
|
|
* @return FormField |
291
|
|
|
*/ |
292
|
|
|
public function scaffoldFormField($title = null) { |
293
|
|
|
$field = new MoneyField($this->name); |
294
|
|
|
$field->setAllowedCurrencies($this->getAllowedCurrencies()); |
295
|
|
|
$field->setLocale($this->getLocale()); |
296
|
|
|
|
297
|
|
|
return $field; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* For backwards compatibility reasons |
302
|
|
|
* (mainly with ecommerce module), |
303
|
|
|
* this returns the amount value of the field, |
304
|
|
|
* rather than a {@link Nice()} formatting. |
305
|
|
|
*/ |
306
|
|
|
public function __toString() { |
307
|
|
|
return (string)$this->getAmount(); |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
public function scalarValueOnly() |
311
|
|
|
{ |
312
|
|
|
return false; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
} |
316
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.