Test Failed
Push — develop ( 88d89c...00d2c4 )
by Remco
12:20
created

Money::initialize_calculator()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
c 0
b 0
f 0
cc 3
nc 3
nop 0
rs 9.9
1
<?php
2
/**
3
 * Money
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2019 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Money
9
 */
10
11
namespace Pronamic\WordPress\Money;
12
13
use Pronamic\WordPress\Money\Calculator\BcMathCalculator;
14
use Pronamic\WordPress\Money\Calculator\GmpCalculator;
15
use Pronamic\WordPress\Money\Calculator\PhpCalculator;
16
17
/**
18
 * Money
19
 *
20
 * @author Remco Tolsma
21
 * @version 1.2.1
22
 * @since   1.0.0
23
 */
24
class Money {
25
	/**
26
	 * Amount value.
27
	 *
28
	 * @var float
29
	 */
30
	private $value;
31
32
	/**
33
	 * Currency.
34
	 *
35
	 * @var Currency
36
	 */
37
	private $currency;
38
39
	/**
40
	 * Calculator.
41
	 *
42
	 * @var Calculator
43
	 */
44
	private static $calculator;
45
46
	/**
47
	 * Calculators.
48
	 *
49
	 * @var array
50
	 */
51
	private static $calculators = [
52
		BcMathCalculator::class,
53
		PhpCalculator::class,
54
	];
55
56
	/**
57
	 * Construct and initialize money object.
58
	 *
59
	 * @param string|int|float $value    Amount value.
60
	 * @param Currency|string  $currency Currency.
61
	 */
62
	public function __construct( $value = 0, $currency = 'EUR' ) {
63
		$this->set_value( $value );
64
		$this->set_currency( $currency );
65
	}
66
67
	/**
68
	 * Get default format.
69
	 *
70
	 * @return string
71
	 */
72
	public static function get_default_format() {
73
		/* translators: 1: currency symbol, 2: amount value, 3: currency code, note: use non-breaking space! */
74
		$format = _x( '%1$s%2$s %3$s', 'money format', 'pronamic-money' );
75
		// Note:               ↳ Non-breaking space.
76
		$format = apply_filters( 'pronamic_money_default_format', $format );
77
78
		return $format;
79
	}
80
81
	/**
82
	 * Format i18n.
83
	 *
84
	 * @param string|null $format Format.
85
	 *
86
	 * @return string
87
	 */
88
	public function format_i18n( $format = null ) {
89
		if ( is_null( $format ) ) {
90
			$format = self::get_default_format();
91
		}
92
93
		$alphabetic_code = $this->currency->get_alphabetic_code();
94
95
		if ( ! empty( $alphabetic_code ) ) {
96
			$number_decimals = $this->currency->get_number_decimals();
97
98
			// Handle non trailing zero formatter.
99
			if ( false !== strpos( $format, '%2$NTZ' ) ) {
100
				$decimals = substr( $this->format(), ( - 1 * $number_decimals ), $number_decimals );
101
102
				if ( 0 === (int) $decimals ) {
103
					$number_decimals = 0;
104
				}
105
106
				$format = str_replace( '%2$NTZ', '%2$s', $format );
107
			}
108
109
			return sprintf(
110
				$format,
111
				$this->currency->get_symbol(),
112
				number_format_i18n( $this->get_value(), $number_decimals ),
113
				$this->currency->get_alphabetic_code()
114
			);
115
		}
116
117
		return number_format_i18n( $this->get_value(), 2 );
118
	}
119
120
	/**
121
	 * Format i18n without trailing zeros.
122
	 *
123
	 * @param string|null $format Format.
124
	 *
125
	 * @return string
126
	 */
127
	public function format_i18n_non_trailing_zeros( $format = null ) {
128
		if ( is_null( $format ) ) {
129
			$format = self::get_default_format();
130
		}
131
132
		$format = str_replace( '%2$s', '%2$NTZ', $format );
133
134
		return $this->format_i18n( $format );
135
	}
136
137
	/**
138
	 * Format.
139
	 *
140
	 * @param string|null $format Format.
141
	 *
142
	 * @return string
143
	 */
144
	public function format( $format = null ) {
145
		if ( is_null( $format ) ) {
146
			$format = '%2$s';
147
		}
148
149
		$alphabetic_code = $this->currency->get_alphabetic_code();
150
151
		if ( ! empty( $alphabetic_code ) ) {
152
			return sprintf(
153
				$format,
154
				$this->currency->get_symbol(),
155
				number_format( $this->get_value(), $this->get_currency()->get_number_decimals(), '.', '' ),
156
				$this->currency->get_alphabetic_code()
157
			);
158
		}
159
160
		return number_format( $this->get_value(), 2, '.', '' );
161
	}
162
163
	/**
164
	 * Get value.
165
	 *
166
	 * @return float Amount value.
167
	 */
168
	public function get_value() {
169
		return $this->value;
170
	}
171
172
	/**
173
	 * Get amount.
174
	 *
175
	 * @deprecated 1.2.0
176
	 * @return float Amount value.
177
	 */
178
	public function get_amount() {
179
		_deprecated_function( __METHOD__, '1.2.0', 'Money::get_value()' );
180
181
		return $this->get_value();
182
	}
183
184
	/**
185
	 * Get cents.
186
	 *
187
	 * @return float
188
	 *
189
	 * @deprecated 1.2.2 Use `Money::get_minor_units()` instead.
190
	 */
191
	public function get_cents() {
192
		return (float) $this->get_minor_units();
193
	}
194
195
	/**
196
	 * Get amount in minor units.
197
	 *
198
	 * Examples for value 10:
199
	 *   JPY 0 decimals: 10
200
	 *   EUR 2 decimals: 1000
201
	 *   BHD 3 decimals: 10000
202
	 *   NLG 4 decimals: 100000
203
	 *
204
	 * @since 1.2.1
205
	 *
206
	 * @return int
207
	 */
208
	public function get_minor_units() {
209
		$calculator = $this->get_calculator();
210
211
		$minor_units = $calculator->multiply( strval( $this->get_value() ), pow( 10, $this->currency->get_number_decimals() ) );
212
213
		return (int) $minor_units;
214
	}
215
216
	/**
217
	 * Set value.
218
	 *
219
	 * @param mixed $value Amount value.
220
	 */
221
	public function set_value( $value ) {
222
		$this->value = floatval( $value );
223
	}
224
225
	/**
226
	 * Set amount.
227
	 *
228
	 * @deprecated 1.2.0
229
	 * @param mixed $value Amount value.
230
	 */
231
	public function set_amount( $value ) {
232
		_deprecated_function( __METHOD__, '1.2.0', 'Money::set_value()' );
233
234
		$this->set_value( $value );
235
	}
236
237
	/**
238
	 * Get currency.
239
	 *
240
	 * @return Currency
241
	 */
242
	public function get_currency() {
243
		return $this->currency;
244
	}
245
246
	/**
247
	 * Set currency.
248
	 *
249
	 * @param string|Currency $currency Currency.
250
	 */
251
	public function set_currency( $currency ) {
252
		if ( $currency instanceof Currency ) {
253
			$this->currency = $currency;
254
255
			return;
256
		}
257
258
		$this->currency = Currency::get_instance( $currency );
259
	}
260
261
	/**
262
	 * Create a string representation of this money object.
263
	 *
264
	 * @return string
265
	 */
266
	public function __toString() {
267
		return $this->format_i18n();
268
	}
269
270
	/**
271
	 * Returns a new Money object that represents
272
	 * the sum of this and an other Money object.
273
	 *
274
	 * @param Money $addend Addend.
275
	 *
276
	 * @return Money
277
	 */
278 View Code Duplication
	public function add( Money $addend ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
279
		$value = $this->get_value();
280
281
		$calculator = $this->get_calculator();
282
283
		$value = $calculator->add( strval( $value ), strval( $addend->get_value() ) );
284
285
		return new self( $value, $this->get_currency() );
286
	}
287
288
	/**
289
	 * Returns a new Money object that represents
290
	 * the difference of this and an other Money object.
291
	 *
292
	 * @link https://github.com/moneyphp/money/blob/v3.2.1/src/Money.php#L235-L255
293
	 *
294
	 * @param Money $subtrahend Subtrahend.
295
	 *
296
	 * @return Money
297
	 */
298 View Code Duplication
	public function subtract( Money $subtrahend ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
299
		$value = $this->get_value();
300
301
		$calculator = $this->get_calculator();
302
303
		$value = $calculator->subtract( strval( $value ), strval( $subtrahend->get_value() ) );
304
305
		return new self( $value, $this->get_currency() );
306
	}
307
308
	/**
309
	 * Initialize calculator.
310
	 *
311
	 * @return Calculator
312
	 *
313
	 * @throws \RuntimeException If cannot find calculator for money calculations.
314
	 */
315
	private static function initialize_calculator() {
316
		$calculators = self::$calculators;
317
318
		foreach ( $calculators as $calculator ) {
319
			if ( $calculator::supported() ) {
320
				return new $calculator();
321
			}
322
		}
323
324
		throw new \RuntimeException( 'Cannot find calculator for money calculations' );
325
	}
326
327
	/**
328
	 * Get calculator.
329
	 *
330
	 * @return Calculator
331
	 */
332
	protected function get_calculator() {
333
		if ( null === self::$calculator ) {
334
			self::$calculator = self::initialize_calculator();
335
		}
336
337
		return self::$calculator;
338
	}
339
}
340