Completed
Push — correct-classname-values ( f9b487 )
by Sam
08:29
created

MoneyField::buildCurrencyField()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 22
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 17
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 22
rs 9.2
1
<?php
2
3
4
5
use SilverStripe\ORM\FieldType\DBField;
6
use SilverStripe\ORM\FieldType\DBMoney;
7
use SilverStripe\ORM\DataObjectInterface;
8
9
10
/**
11
 * A form field that can save into a {@link Money} database field.
12
 * See {@link CurrencyField} for a similiar implementation
13
 * that can save into a single float database field without indicating the currency.
14
 *
15
 * @author Ingo Schommer, SilverStripe Ltd. (<firstname>@silverstripe.com)
16
 *
17
 * @package forms
18
 * @subpackage fields-formattedinput
19
 */
20
class MoneyField extends FormField {
21
22
	protected $schemaDataType = FormField::SCHEMA_DATA_TYPE_TEXT;
23
24
	/**
25
	 * @var string $_locale
26
	 */
27
	protected $_locale;
28
29
	/**
30
	 * Limit the currencies
31
	 * @var array $allowedCurrencies
32
	 */
33
	protected $allowedCurrencies;
34
35
	/**
36
	 * @var NumericField
37
	 */
38
	protected $fieldAmount = null;
39
40
	/**
41
	 * @var FormField
42
	 */
43
	protected $fieldCurrency = null;
44
45
	/**
46
	 * Gets field for the currency selector
47
	 *
48
	 * @return FormField
49
	 */
50
	public function getCurrencyField() {
51
		return $this->fieldCurrency;
52
	}
53
54
	/**
55
	 * Gets field for the amount input
56
	 *
57
	 * @return NumericField
58
	 */
59
	public function getAmountField() {
60
		return $this->fieldAmount;
61
	}
62
63
	public function __construct($name, $title = null, $value = "") {
64
		$this->setName($name);
65
66
		// naming with underscores to prevent values from actually being saved somewhere
67
		$this->fieldAmount = new NumericField("{$name}[Amount]", _t('MoneyField.FIELDLABELAMOUNT', 'Amount'));
68
		$this->fieldCurrency = $this->buildCurrencyField();
69
70
		parent::__construct($name, $title, $value);
71
	}
72
73
	public function __clone()
74
	{
75
		$this->fieldAmount = clone $this->fieldAmount;
76
		$this->fieldCurrency = clone $this->fieldCurrency;
77
	}
78
79
	/**
80
	 * Builds a new currency field based on the allowed currencies configured
81
	 *
82
	 * @return FormField
83
	 */
84
	protected function buildCurrencyField() {
85
		$name = $this->getName();
86
		$allowedCurrencies = $this->getAllowedCurrencies();
87
		if($allowedCurrencies) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $allowedCurrencies of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
88
			$field = new DropdownField(
89
				"{$name}[Currency]",
90
				_t('MoneyField.FIELDLABELCURRENCY', 'Currency'),
91
				ArrayLib::is_associative($allowedCurrencies)
92
					? $allowedCurrencies
93
					: array_combine($allowedCurrencies,$allowedCurrencies)
94
			);
95
		} else {
96
			$field = new TextField(
97
				"{$name}[Currency]",
98
				_t('MoneyField.FIELDLABELCURRENCY', 'Currency')
99
			);
100
		}
101
102
		$field->setReadonly($this->isReadonly());
103
		$field->setDisabled($this->isDisabled());
104
		return $field;
105
	}
106
107
	public function setValue($val) {
108
		$this->value = $val;
109
110
		if(is_array($val)) {
111
			$this->fieldCurrency->setValue($val['Currency']);
112
			$this->fieldAmount->setValue($val['Amount']);
113
		} elseif($val instanceof DBMoney) {
114
			$this->fieldCurrency->setValue($val->getCurrency());
115
			$this->fieldAmount->setValue($val->getAmount());
116
		}
117
118
		// @todo Format numbers according to current locale, incl.
119
		//  decimal and thousands signs, while respecting the stored
120
		//  precision in the database without truncating it during display
121
		//  and subsequent save operations
122
123
		return $this;
124
	}
125
126
	/**
127
	 * 30/06/2009 - Enhancement:
128
	 * SaveInto checks if set-methods are available and use them
129
	 * instead of setting the values in the money class directly. saveInto
130
	 * initiates a new Money class object to pass through the values to the setter
131
	 * method.
132
	 *
133
	 * (see @link MoneyFieldTest_CustomSetter_Object for more information)
134
	 *
135
	 * @param DataObjectInterface|Object $dataObject
136
	 */
137
	public function saveInto(DataObjectInterface $dataObject) {
138
		$fieldName = $this->getName();
139
		if($dataObject->hasMethod("set$fieldName")) {
140
			$dataObject->$fieldName = DBField::create_field('Money', array(
141
				"Currency" => $this->fieldCurrency->dataValue(),
142
				"Amount" => $this->fieldAmount->dataValue()
143
			));
144
		} else {
145
			$currencyField = "{$fieldName}Currency";
146
			$amountField = "{$fieldName}Amount";
147
148
			$dataObject->$currencyField = $this->fieldCurrency->dataValue();
149
			$dataObject->$amountField = $this->fieldAmount->dataValue();
150
		}
151
	}
152
153
	/**
154
	 * Returns a readonly version of this field.
155
	 */
156
	public function performReadonlyTransformation() {
157
		$clone = clone $this;
158
		$clone->fieldAmount = $clone->fieldAmount->performReadonlyTransformation();
0 ignored issues
show
Documentation Bug introduced by
It seems like $clone->fieldAmount->per...eadonlyTransformation() of type object<NumericField_Readonly> is incompatible with the declared type object<NumericField> of property $fieldAmount.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
159
		$clone->fieldCurrency = $clone->fieldCurrency->performReadonlyTransformation();
160
		$clone->setReadonly(true);
161
		return $clone;
162
	}
163
164
	public function setReadonly($bool) {
165
		parent::setReadonly($bool);
166
167
		$this->fieldAmount->setReadonly($bool);
168
		$this->fieldCurrency->setReadonly($bool);
169
170
		return $this;
171
	}
172
173
	public function setDisabled($bool) {
174
		parent::setDisabled($bool);
175
176
		$this->fieldAmount->setDisabled($bool);
177
		$this->fieldCurrency->setDisabled($bool);
178
179
		return $this;
180
	}
181
182
	/**
183
	 * @param array $arr
184
	 * @return $this
185
	 */
186
	public function setAllowedCurrencies($arr) {
187
		$this->allowedCurrencies = $arr;
188
189
		// @todo Has to be done twice in case allowed currencies changed since construction
190
		$oldVal = $this->fieldCurrency->dataValue();
191
		$this->fieldCurrency = $this->buildCurrencyField();
192
		$this->fieldCurrency->setValue($oldVal);
193
194
		return $this;
195
	}
196
197
	/**
198
	 * @return array
199
	 */
200
	public function getAllowedCurrencies() {
201
		return $this->allowedCurrencies;
202
	}
203
204
	public function setLocale($locale) {
205
		$this->_locale = $locale;
206
		return $this;
207
	}
208
209
	public function getLocale() {
210
		return $this->_locale;
211
	}
212
213
	/**
214
	 * Validate this field
215
	 *
216
	 * @param Validator $validator
217
	 * @return bool
218
	 */
219
	public function validate($validator) {
220
		return !(is_null($this->fieldAmount) || is_null($this->fieldCurrency));
221
	}
222
223
	public function setForm($form) {
224
		$this->fieldCurrency->setForm($form);
225
		$this->fieldAmount->setForm($form);
226
		return parent::setForm($form);
227
	}
228
}
229