Failed Conditions
Push — develop ( eeffa3...7ffcfa )
by Remco
04:13
created

src/Money.php (1 issue)

1
<?php
2
/**
3
 * Money
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2021 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Money
9
 */
10
11
namespace Pronamic\WordPress\Money;
12
13
use JsonSerializable;
14
use Pronamic\WordPress\Number\Number;
15
16
/**
17
 * Money
18
 *
19
 * @author Remco Tolsma
20
 * @version 2.0.0
21
 * @since   1.0.0
22
 */
23
class Money implements JsonSerializable {
24
	/**
25
	 * Number.
26
	 *
27
	 * @var Number
28
	 */
29
	private $amount;
30
31
	/**
32
	 * Currency.
33
	 *
34
	 * @var Currency
35
	 */
36
	private $currency;
37
38
	/**
39
	 * Construct and initialize money object.
40
	 *
41
	 * @param mixed           $value    Amount value.
42
	 * @param Currency|string $currency Currency.
43
	 */
44 101
	public function __construct( $value = 0, $currency = 'EUR' ) {
45 101
		$this->set_value( $value );
46 101
		$this->set_currency( $currency );
47 101
	}
48
49
	/**
50
	 * Get default format.
51
	 *
52
	 * @return string
53
	 */
54 17
	public static function get_default_format() {
55
		/* translators: 1: currency symbol, 2: amount value, 3: currency code, note: use non-breaking space! */
56 17
		$format = _x( '%1$s%2$s %3$s', 'money format', 'pronamic-money' );
57
		// Note:               ↳ Non-breaking space.
58 17
		$format = apply_filters( 'pronamic_money_default_format', $format );
59
60 17
		return $format;
61
	}
62
63
	/**
64
	 * Format i18n.
65
	 *
66
	 * @param string|null $format Format.
67
	 *
68
	 * @return string
69
	 */
70 14
	public function format_i18n( $format = null ) {
71 14
		if ( is_null( $format ) ) {
72 7
			$format = self::get_default_format();
73
		}
74
75 14
		$alphabetic_code = $this->currency->get_alphabetic_code();
76 14
		$number_decimals = $this->currency->get_number_decimals();
77
78
		// Handle non trailing zero formatter.
79 14
		if ( false !== \strpos( $format, '%2$NTZ' ) ) {
80 7
			$decimals = \substr( $this->format(), ( - 1 * $number_decimals ), $number_decimals );
81
82 7
			if ( 0 === (int) $decimals ) {
83 5
				$number_decimals = 0;
84
			}
85
86 7
			$format = \str_replace( '%2$NTZ', '%2$s', $format );
87
		}
88
89 14
		return \sprintf(
90 14
			$format,
91 14
			(string) $this->currency->get_symbol(),
92 14
			$this->amount->format_i18n( $number_decimals ),
93 14
			\strval( $alphabetic_code )
94
		);
95
	}
96
97
	/**
98
	 * Format i18n without trailing zeros.
99
	 *
100
	 * @param string|null $format Format.
101
	 *
102
	 * @return string
103
	 */
104 7
	public function format_i18n_non_trailing_zeros( $format = null ) {
105 7
		if ( is_null( $format ) ) {
106 7
			$format = self::get_default_format();
107
		}
108
109 7
		$format = str_replace( '%2$s', '%2$NTZ', $format );
110
111 7
		return $this->format_i18n( $format );
112
	}
113
114
	/**
115
	 * Format.
116
	 *
117
	 * @param string|null $format Format.
118
	 *
119
	 * @return string
120
	 */
121 7
	public function format( $format = null ) {
122 7
		if ( is_null( $format ) ) {
123 7
			$format = '%2$s';
124
		}
125
126 7
		$alphabetic_code = $this->currency->get_alphabetic_code();
127
128 7
		return \sprintf(
129 7
			$format,
130 7
			(string) $this->currency->get_symbol(),
131 7
			$this->amount->format( $this->get_currency()->get_number_decimals() ),
132 7
			\strval( $alphabetic_code )
133
		);
134
	}
135
136
	/**
137
	 * Number format.
138
	 * 
139
	 * @param int         $decimals            Precision of the number of decimal places.
140
	 * @param string|null $decimal_separator   Sets the separator for the decimal point.
141
	 * @param string|null $thousands_separator Sets the thousands separator.
142
	 * @return string
143
	 */
144 6
	public function number_format( $decimals = null, $decimal_separator = '.', $thousands_separator = ',' ) {
145 6
		if ( null === $decimals ) {
146 6
			$decimals = $this->currency->get_number_decimals();
147
		}
148
149 6
		return $this->amount->format( $decimals, $decimal_separator, $thousands_separator );
150
	}
151
152
	/**
153
	 * Number format i18n.
154
	 * 
155
	 * @param int $decimals Precision of the number of decimal places.
156
	 * @return string
157
	 */
158 1
	public function number_format_i18n( $decimals = null ) {
159 1
		if ( null === $decimals ) {
160 1
			$decimals = $this->currency->get_number_decimals();
161
		}
162
163 1
		return $this->amount->format_i18n( $decimals );
164
	}
165
166
	/**
167
	 * Get value.
168
	 *
169
	 * @return string Amount value.
170
	 */
171 62
	public function get_value() {
172 62
		return $this->amount->get_value();
173
	}
174
175
	/**
176
	 * Get number.
177
	 *
178
	 * @return Number
179
	 */
180 2
	public function get_number() {
181 2
		return $this->amount;
182
	}
183
184
	/**
185
	 * Get amount in minor units.
186
	 *
187
	 * Examples for value 10:
188
	 *   JPY 0 decimals: 10
189
	 *   EUR 2 decimals: 1000
190
	 *   BHD 3 decimals: 10000
191
	 *   NLG 4 decimals: 100000
192
	 *
193
	 * @link https://en.wikipedia.org/wiki/Cent_(currency)
194
	 * @link https://simple.wikipedia.org/wiki/ISO_4217
195
	 * @since 1.2.1
196
	 * @return Number
197
	 */
198 16
	public function get_minor_units() {
199 16
		return $this->amount->multiply( Number::from_mixed( \pow( 10, $this->currency->get_number_decimals() ) ) );
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->amount->mu...et_number_decimals()))) returns the type double|integer which is incompatible with the documented return type Pronamic\WordPress\Number\Number.
Loading history...
200
	}
201
202
	/**
203
	 * Set value.
204
	 *
205
	 * @param mixed $value Amount value.
206
	 * @return void
207
	 */
208 101
	final public function set_value( $value ) {
209 101
		$this->amount = Number::from_mixed( $value );
210 101
	}
211
212
	/**
213
	 * Get currency.
214
	 *
215
	 * @return Currency
216
	 */
217 10
	public function get_currency() {
218 10
		return $this->currency;
219
	}
220
221
	/**
222
	 * Set currency.
223
	 *
224
	 * @param string|Currency $currency Currency.
225
	 * @return void
226
	 */
227 101
	final public function set_currency( $currency ) {
228 101
		if ( ! $currency instanceof Currency ) {
229 101
			$currency = Currency::get_instance( $currency );
230
		}
231
232 101
		$this->currency = $currency;
233 101
	}
234
235
	/**
236
	 * Create a string representation of this money object.
237
	 *
238
	 * @return string
239
	 */
240 1
	public function __toString() {
241 1
		return \sprintf(
242 1
			'%s %s',
243 1
			$this->currency->get_alphabetic_code(),
244 1
			$this->amount->format( $this->get_currency()->get_number_decimals() )
245
		);
246
	}
247
248
	/**
249
	 * JSON serialize.
250
	 *
251
	 * @link https://www.php.net/manual/en/jsonserializable.jsonserialize.php
252
	 * @return object
253
	 */
254 2
	public function jsonSerialize() {
255
		return (object) array(
256 2
			'value'    => $this->amount->get_value(),
257 2
			'currency' => $this->currency->jsonSerialize(),
258
		);
259
	}
260
261
	/**
262
	 * Returns a new Money object that represents
263
	 * the sum of this and an other Money object.
264
	 *
265
	 * @param Money $addend Addend.
266
	 *
267
	 * @return Money
268
	 */
269 1
	public function add( Money $addend ) {
270 1
		$result = $this->amount->add( $addend->get_number() );
271
272 1
		return new static( $result, $this->currency );
273
	}
274
275
	/**
276
	 * Returns a new Money object that represents
277
	 * the difference of this and an other Money object.
278
	 *
279
	 * @link https://github.com/moneyphp/money/blob/v3.2.1/src/Money.php#L235-L255
280
	 *
281
	 * @param Money $subtrahend Subtrahend.
282
	 *
283
	 * @return Money
284
	 */
285 1
	public function subtract( Money $subtrahend ) {
286 1
		$result = $this->amount->subtract( $subtrahend->get_number() );
287
288 1
		return new static( $result, $this->currency );
289
	}
290
291
	/**
292
	 * Returns a new Money object that represents
293
	 * the multiplied value of this Money object.
294
	 *
295
	 * @link https://github.com/moneyphp/money/blob/v3.2.1/src/Money.php#L299-L316
296
	 *
297
	 * @param mixed $multiplier Multiplier.
298
	 *
299
	 * @return Money
300
	 */
301 1
	public function multiply( $multiplier ) {
302 1
		$multiplier = Number::from_mixed( $multiplier );
303
304 1
		$result = $this->amount->multiply( $multiplier );
305
306 1
		return new static( $result, $this->currency );
307
	}
308
309
	/**
310
	 * Returns a new Money object that represents
311
	 * the divided value of this Money object.
312
	 *
313
	 * @link https://github.com/moneyphp/money/blob/v3.2.1/src/Money.php#L318-L341
314
	 *
315
	 * @param mixed $divisor Divisor.
316
	 *
317
	 * @return Money
318
	 */
319 1
	public function divide( $divisor ) {
320 1
		$divisor = Number::from_mixed( $divisor );
321
322 1
		$result = $this->amount->divide( $divisor );
323
324 1
		return new static( $result, $this->currency );
325
	}
326
327
	/**
328
	 * Absolute.
329
	 *
330
	 * @link https://github.com/moneyphp/money/blob/v4.0.1/src/Money.php#L411-L417
331
	 * @return Money
332
	 */
333 1
	public function absolute() {
334 1
		return new static(
335 1
			$this->amount->absolute(),
336 1
			$this->currency
337
		);
338
	}
339
}
340